我正在学习如何使用 ExecutorService
在 Java 中使用线程池,这是我正在处理的一个例子:
public class Example {
static class WorkerThread implements Runnable {
private String command;
public WorkerThread(String s) {
this.command = s;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Start. Command = " + command);
processCommand();
System.out.println(Thread.currentThread().getName() + " End.");
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return this.command;
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread("" + i);
executor.execute(worker);
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.SECONDS);
// while (!executor.isTerminated()) {
// }
System.out.println("Finished all threads");
}
}
我有两个问题:
我应该如何等待
ExecutorService
终止,我应该使用awaitTermination()
还是isTerminated()
(有人建议后者是一种错误的方式(?Runnable
是否正确添加到执行器,还是应该submit()
与Future<T>
回调一起使用?
这可能取决于上下文,所以请您解释一下(对于这两个问题(我何时应该使用提到的每个解决方案。
这个程序不是在等待线程终止,JVM正在等待: 我得到的输出是:
pool-1-thread-1 Start. Command = 0
pool-1-thread-2 Start. Command = 1
pool-1-thread-3 Start. Command = 2
pool-1-thread-4 Start. Command = 3
pool-1-thread-5 Start. Command = 4
Finished all threads
pool-1-thread-2 End.
pool-1-thread-1 End.
pool-1-thread-4 End.
pool-1-thread-1 Start. Command = 5
pool-1-thread-3 End.
pool-1-thread-2 Start. Command = 7
pool-1-thread-5 End.
pool-1-thread-4 Start. Command = 6
pool-1-thread-5 Start. Command = 9
pool-1-thread-3 Start. Command = 8
pool-1-thread-3 End.
pool-1-thread-5 End.
pool-1-thread-4 End.
pool-1-thread-1 End.
pool-1-thread-2 End.
您会注意到Finished all threads
不在底部。如果要等待所有线程完成,请使用以下命令:
public class Example {
static class WorkerThread implements Runnable {
private String command;
public WorkerThread(String s) {
this.command = s;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Start. Command = " + command);
processCommand();
System.out.println(Thread.currentThread().getName() + " End.");
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return this.command;
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(5);
List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
for (int i = 0; i < 10; i++) {
tasks.add(Executors.callable(new WorkerThread("" + i)));
}
executor.invokeAll(tasks);
System.out.println("Finished all threads");
// this merely terminates the ExecutorService, otherwise the JVM will never close.
executor.shutdown();
executor.awaitTermination(10L, TimeUnit.SECONDS);
}
}
您会注意到正确的输出:
pool-1-thread-1 Start. Command = 0
pool-1-thread-5 Start. Command = 4
pool-1-thread-4 Start. Command = 3
pool-1-thread-3 Start. Command = 2
pool-1-thread-2 Start. Command = 1
pool-1-thread-3 End.
pool-1-thread-1 End.
pool-1-thread-5 End.
pool-1-thread-3 Start. Command = 5
pool-1-thread-2 End.
pool-1-thread-4 End.
pool-1-thread-2 Start. Command = 8
pool-1-thread-1 Start. Command = 7
pool-1-thread-5 Start. Command = 6
pool-1-thread-4 Start. Command = 9
pool-1-thread-1 End.
pool-1-thread-4 End.
pool-1-thread-3 End.
pool-1-thread-5 End.
pool-1-thread-2 End.
Finished all threads
实现它的几种方法:(a( 在while (!executor.isTerminated())
内呼叫awaitTermination(long someTime, TimeUnit ....)
。(b( 将所有可调用对象存储在集合对象中并调用executor.invokeAll(....)
。这将等到执行程序服务完成所有任务。
1.我应该如何等待执行服务终止,我应该使用 awaitTermination(( 还是 isTerminated(((有人建议后者是错误的方式(?
- 您可以在
shutdown()
后使用awaitTermination()
或 - 您可以通过传递可运行/可调用任务列表在执行器服务上使用
invokeAll()
或 - 您可以使用
CountDownLatch
有关更多详细信息,请查看相关的 SE 问题:
如何使用执行器服务等待所有线程完成?
执行器服务,如何等待所有任务完成
等待所有线程完成,然后再关闭执行程序
2.Runnables是否正确添加到执行器中,或者我应该将submit((与未来回调一起使用?
- 如果只想运行命令而不等待结果,请使用
Runnable
- 如果要在执行后检查任务的结果,请使用
Callable
如果你使用 submit()
,异常隐藏在框架中,你必须注意正确处理异常。
查看相关的 SE 问题:
在 ExecutorService 的提交和 ExecutorService 的执行之间进行选择
executor.submit 和 executor.execute 在 Java 中的这段代码中的区别?