我是并发的新手,我正试图实现一个do-while循环的执行器服务并发。但是我总是碰到RejectedExecutionException
do {
Future<Void> future = executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
// action
return null;
}
});
futures.add(future);
executor.shutdown();
for (Future<Void> future : futures) {
try {
future.get();
}
catch (InterruptedException e) {
throw new IOException(e)
}
}
}
while (true);
但这似乎不正确。我想我在错误的地方呼吁关闭。谁能帮我正确地实现Executor Service in a do-while
环?谢谢。
ExecutorService.shutdown()停止ExecutorService
接受任何作业。它应该在你完成提交作业时被调用。
future .get()也是一个阻塞方法,这意味着它将阻塞当前线程的执行,并且循环的下一次迭代将不会继续,除非这个future(调用get的future)返回。这将在每次迭代中发生,这使得代码是非并行的。
你可以使用CountDownLatch来等待所有的作业返回。
正确代码如下:
final List<Object> results = Collections.synchronizedList(new ArrayList<Object>());
final CountDownLatch latch = new CountDownLatch(10);//suppose you'll have 10 futures
do {
Future<Void> future = executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
// action
latch.countDown();//decrease the latch count
results.add(result); // some result
return null;
}
});
futures.add(future);
} while (true);
executor.shutdown();
latch.await(); //This will block till latch.countDown() has been called 10 times.
//Now results has all the outputs, do what you want with them.
如果你使用的是Java 8那么你可以看看这个答案https://stackoverflow.com/a/36261808/5343269
您是对的,shutdown
方法没有在正确的时间被调用。在shutdown
被调用后,ExecutorService
将不接受任务(除非你实现了自己的版本)。
您应该在已经将所有任务提交给执行器之后调用shutdown
,因此在本例中,在do-while
循环之后的某个地方。
来自ThreadPoolExecutor文档:
拒绝任务
在execute(Runnable)方法中提交的新任务将在Executor被关闭时被拒绝,并且当Executor为最大线程和工作队列容量使用有限界限并且饱和时。
无论哪种情况,execute方法都调用RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor)
method of its RejectedExecutionHandler
从你的代码中,很明显你首先调用shutdown()
,然后提交任务。
另一方面,请参考以下相关的SE问题,了解关闭ExecutorService
的正确方法:
ExecutorService's shutdown()不会等到所有线程都完成