我正在开展一个项目,其中我将有不同的Bundles / Models。我们举一个例子,假设我有4个包,每个包都有一个方法名process
。
以下是我应该做的事情 -
process method
,并且每个bundle中的process method
将返回一个map,然后将该映射写入同一个线程中的数据库或者其他任何内容最好的方法(我不确定这是正确的方法)。我所做的以下尝试很可能是有缺陷的,并且错误处理绝不是完整的。任何人都可以指导我在错误处理案例中应该做些什么吗?
下面是我的方法,它将以多线程方式调用所有包中的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;
}
}
有谁能告诉我上述方法是否有任何问题,还是有更好,更有效的方法做同样的事情?我不确定是否存在任何线程安全问题。
任何帮助都将受到赞赏。
答案 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
方法时都创建一个。