我的问题:如何在ThreadPoolExecutor
上执行一堆线程对象并等待它们全部完成后再继续?
我是ThreadPoolExecutor的新手。因此,此代码是一项测试,以了解它是如何工作的。现在我甚至没有用BlockingQueue
填充对象,因为我不知道如何在没有用另一个execute()
调用RunnableObject
的情况下启动队列。无论如何,现在我只是打电话给awaitTermination()
,但我想我仍然缺少一些东西。任何提示都会很棒!感谢。
public void testThreadPoolExecutor() throws InterruptedException {
int limit = 20;
BlockingQueue q = new ArrayBlockingQueue(limit);
ThreadPoolExecutor ex = new ThreadPoolExecutor(limit, limit, 20, TimeUnit.SECONDS, q);
for (int i = 0; i < limit; i++) {
ex.execute(new RunnableObject(i + 1));
}
ex.awaitTermination(2, TimeUnit.SECONDS);
System.out.println("finished");
}
RunnableObject类:
package playground;
public class RunnableObject implements Runnable {
private final int id;
public RunnableObject(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("ID: " + id + " started");
try {
Thread.sleep(2354);
} catch (InterruptedException ignore) {
}
System.out.println("ID: " + id + " ended");
}
}
答案 0 :(得分:48)
你应该循环awaitTermination
ExecutorService threads;
// ...
// Tell threads to finish off.
threads.shutdown();
// Wait for everything to finish.
while (!threads.awaitTermination(10, TimeUnit.SECONDS)) {
log.info("Awaiting completion of threads.");
}
答案 1 :(得分:4)
您的问题似乎是在将所有作业提交到池后,您没有致电shutdown
。如果没有shutdown()
,您的awaitTermination
将始终返回false。
ThreadPoolExecutor ex =
new ThreadPoolExecutor(limit, limit, 20, TimeUnit.SECONDS, q);
for (int i = 0; i < limit; i++) {
ex.execute(new RunnableObject(i + 1));
}
// you are missing this line!!
ex.shutdown();
ex.awaitTermination(2, TimeUnit.SECONDS);
您还可以执行以下操作,等待所有工作完成:
List<Future<Object>> futures = new ArrayList<Future<Object>>();
for (int i = 0; i < limit; i++) {
futures.add(ex.submit(new RunnableObject(i + 1), (Object)null));
}
for (Future<Object> future : futures) {
// this joins with the submitted job
future.get();
}
...
// still need to shutdown at the end
ex.shutdown();
此外,由于您正在等待2354
毫秒,但仅等待2
SECONDS
的所有作业终止,awaitTermination
将始终返回{{1} }}
最后,听起来你担心创建一个新的false
而你又想重用第一个ThreadPoolExecutor
。不要。与您编写的用于检测作业是否完成的任何代码相比,GC开销将极低。
引用javadocs ThreadPoolExecutor.shutdown()
:
启动有序关闭,其中先前提交的任务已执行,但不会接受任何新任务。如果已经关闭,调用没有额外的效果。
在ThreadPoolExecutor.awaitTermination(...)
方法中,它正在等待执行程序的状态转到TERMINATED
。但首先,如果调用SHUTDOWN
,则州必须转到shutdown()
;如果调用STOP
,则必须转到shutdownNow()
。
答案 2 :(得分:3)
这与执行者本身无关。只需使用界面java.util.concurrent.ExecutorService.invokeAll(Collection<? extends Callable<T>>)
即可。它将一直阻塞,直到所有Callable
完成。
执行者意味着长寿;超出一组任务的生命周期。 shutdown
适用于应用程序完成和清理的时间。
答案 3 :(得分:2)
如果/当抛出InterruptedException时,这是一个处理重试的接受答案的变体:
executor.shutdown();
boolean isWait = true;
while (isWait)
{
try
{
isWait = !executor.awaitTermination(10, TimeUnit.SECONDS);
if (isWait)
{
log.info("Awaiting completion of bulk callback threads.");
}
} catch (InterruptedException e) {
log.debug("Interruped while awaiting completion of callback threads - trying again...");
}
}
答案 4 :(得分:1)
另一种方法是使用CompletionService,如果你必须尝试任何任务结果非常有用:
//run 3 task at time
final int numParallelThreads = 3;
//I used newFixedThreadPool for convenience but if you need you can use ThreadPoolExecutor
ExecutorService executor = Executors.newFixedThreadPool(numParallelThreads);
CompletionService<String> completionService = new ExecutorCompletionService<String>(executor);
int numTaskToStart = 15;
for(int i=0; i<numTaskToStart ; i++){
//task class that implements Callable<String> (or something you need)
MyTask mt = new MyTask();
completionService.submit(mt);
}
executor.shutdown(); //it cannot be queued more task
try {
for (int t = 0; t < numTaskToStart ; t++) {
Future<String> f = completionService.take();
String result = f.get();
// ... something to do ...
}
} catch (InterruptedException e) {
//termination of all started tasks (it returns all not started tasks in queue)
executor.shutdownNow();
} catch (ExecutionException e) {
// ... something to catch ...
}
答案 5 :(得分:-1)
试试这个,
ThreadPoolExecutor ex =
new ThreadPoolExecutor(limit, limit, 20, TimeUnit.SECONDS, q);
for (int i = 0; i < limit; i++) {
ex.execute(new RunnableObject(i + 1));
}
要添加的行
ex.shutdown();
ex.awaitTermination(timeout, unit)