线程安全问题,同时超出每个包的线程

时间:2013-08-31 06:47:17

标签: java multithreading threadpool executorservice futuretask

我正在开展一个项目,其中我将有不同的Bundles / Models。我们举一个例子,假设我有4个包,每个包都有一个方法名process

以下是我应该做的事情 -

  1. 我需要使用多线程并行调用所有这4个Bundles process method,并且每个bundle中的process method将返回一个map,然后将该映射写入同一个线程中的数据库或者其他任何内容最好的方法(我不确定这是正确的方法)。
  2. 我还希望在线程级别启用某种超时功能。意味着如果任何Bundle需要花费大量时间来执行,那么Bundle线程应该获得超时并记录为一个错误,说明这个特定的bundle超时bcoz它需要花费很多时间。
  3. 我所做的以下尝试很可能是有缺陷的,并且错误处理绝不是完整的。任何人都可以指导我在错误处理案例中应该做些什么吗?

    下面是我的方法,它将以多线程方式调用所有包中的process method

    public void processEvents(final Map<String, Object> eventData) {
        ExecutorService pool = Executors.newFixedThreadPool(5);
        List<ProcessBundleHolderEntry> entries = new ArrayList<ProcessBundleHolderEntry>();
    
        Map<String, String> outputs = (Map<String, String>)eventData.get(BConstants.EVENT_HOLDER);
    
        for (BundleRegistration.BundlesHolderEntry entry : BundleRegistration.getInstance()) {
            ProcessBundleHolderEntry processBundleHolderEntry = new ProcessBundleHolderEntry(entry, outputs);
            entries.add(processBundleHolderEntry);
        }
    
        try {
            List<Future<Object>> futures = pool.invokeAll(entries, 30, TimeUnit.SECONDS);
            for (int i = 0; i < futures.size(); i++) {
                // This works since the list of future objects are in the
                // same sequential order as the list of entries
                Future<Object> future = futures.get(i);
                ProcessBundleHolderEntry entry = entries.get(i);
                if (!future.isDone()) {
                    // log error for this entry
                }
            }
        } catch (InterruptedException e) {
            // handle this exception!
        }
    }
    

    其次,为您的线程实现Callable:

    public class ProcessBundleHolderEntry implements Callable {
        private BundleRegistration.BundlesHolderEntry entry;
        private Map<String, String> outputs;
    
        public ProcessBundleHolderEntry(BundleRegistration.BundlesHolderEntry entry, Map<String, String> outputs) {
            this.entry = entry;
            this.outputs = outputs;
        }
    
        public Object call() throws Exception {
            final Map<String, String> response = entry.getPlugin().process(outputs);
            // write to the database.
            System.out.println(response);
            return response;
        }
    }
    

    有谁能告诉我上述方法是否有任何问题,还是有更好,更有效的方法做同样的事情?我不确定是否存在任何线程安全问题。

    任何帮助都将受到赞赏。

1 个答案:

答案 0 :(得分:1)

代码中唯一的共享对象是eventData:只要在此方法运行时未修改它(或者如果地图及其内容是线程安全的并且更改已安全发布),您应该没问题

关于任务的异常处理,通常会执行以下操作:

try {
    future.get();
} catch (ExecutionException e) {
    Throwable exceptionInFuture = e.getCause();
    //throw, log or whatever is appropriate
}

关于中断的异常:它表示正在执行该方法的线程已被中断。你需要做什么取决于你的用例,但你通常应该停止你正在做的事情,所以像这样:

} catch (InterruptedException e) {
    pool.shutdownNow(); //cancels the tasks
    //restore interrupted flag and exit
    Thread.currentThread.interrupt();
    //or rethrow the exception
    throw e;
}

注意:线程池的目的是重用 - 您应该将执行器服务声明为(私有最终)实例变量,而不是每次调用processEvents方法时都创建一个。