我正在使用ExecutorService并提交2个Callables。
你能告诉我使用ExecutorService.awaitTermination和使用Future.get()有什么区别吗?
我不希望线程无限期地继续运行,并且每个Future的例外都不应该影响其他线程的未来。
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<MyObject1> obj1 = null;
if (true) {
task1 = executor.submit(<Callable1>);
}
Future<MyObject2> obj2 = null;
if (<Condition>) {
task2 = executor.submit(<Callable2>);
}
executor.shutdown();
try {
executor.awaitTermination(TIMEOUT_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
}finally {
if( !executor.isTerminated()) {
}
try {
executor.shutdownNow();
}catch(Exception e) {
}
}
MyObject1 myobj1 = null;
try {
myobj1 = task1 != null ? task1.get() : null;
} catch (InterruptedException | ExecutionException e) {
}
MyObject2 myobj2 = null;
try {
myobj2 = task2 != null ? task2.get() : null;
} catch (InterruptedException | ExecutionException e) {
}
答案 0 :(得分:1)
只应在你能告诉我使用ExecutorService.awaitTermination和使用Future.get()有什么区别吗?
ExecutorService.awaitTermination()
请求后调用{p> ExecutorService.shutdown()
。如果在关闭之前调用awaitTermination,则规范不会定义行为。但简而言之,只有在您打算丢弃ExecutorService并且再也不使用它时,才应使用awaitTermination。 Java EE Concurrency规范实际上拒绝调用此方法的应用程序。总的来说,这看起来不是您的用例的正确选项。
Future.get(Timeout)
用于等待特定Future
完成,与想要关闭未来正在运行的ExecutorService
无关。
也相关,请看这个答案:
How to check if all tasks running on ExecutorService are completed
答案 1 :(得分:1)
ExecutorService.awaitTermination
和Future.get(<TimeOut>)
之间的 相似性是两者都是阻塞的。假设您已在线程T
中调用了这些方法中的任何一个,那么T
将被阻止,直到满足与每个方法关联的条件。
在ExecutorService.awaitTermination
的情况下,线程将被阻塞,直到所有任务在关闭请求之后完成执行,或者发生超时,或者当前线程被中断,以先发生者为准。阅读docs。如果Future.get(<TimeOut>)
线程将被阻止,直到提交任务并返回结果或发生异常等,请阅读docs。
之间的差异是每个人的“可用性”,关键驱动因素如下所述:
<强> ExecutorService.awaitTermination
强>
awaitTermination(long timeout, TimeUnit unit)
中指定的时间)时应该使用。通常,人们要么指定{{1}之类的值根据业务需求等待太久或更小的值,例如,如果我等待响应提交给GUI,那么我可能不会等待超过5分钟。 <强> Long.MAX_VALUE
强>
Future.get(<TimeOut>)
。因此,当您调用Callable
时,线程将被阻塞,直到线程返回结果或执行线程中发生某些异常。<小时/> 请参阅下面我创建的示例代码以演示每个代码的可用性,我提供了内联代码注释以便更好地解释。
Future.get(<TimeOut>)
为了你的观点:
我不希望线程无限期地继续运行,也不希望每个线程都运行 Future的例外不应该影响其他线程的Future。
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class ExecutorServiceFutureAndAwaitTermincationExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
testFutureGet(); // after testing comment out this and uncomment below
//testAwaitTermination();
}
private static void testAwaitTermination() throws InterruptedException {
List<Future<String>> futuresList = new ArrayList<>();
final ExecutorService executorService = Executors.newCachedThreadPool();
ExecutorServiceFutureAndAwaitTermincationExample.CallableTask callableTask1 = new ExecutorServiceFutureAndAwaitTermincationExample.CallableTask(2000, true);
ExecutorServiceFutureAndAwaitTermincationExample.CallableTask callableTask2 = new ExecutorServiceFutureAndAwaitTermincationExample.CallableTask(1000, true);
ExecutorServiceFutureAndAwaitTermincationExample.CallableTask callableTask3 = new ExecutorServiceFutureAndAwaitTermincationExample.CallableTask(3000, true);
System.out.println("### Starting submitting tasks");
// submit the callable and register the returned future object so that it can be processed later.
futuresList.add(executorService.submit(callableTask1));
futuresList.add(executorService.submit(callableTask2));
futuresList.add(executorService.submit(callableTask3));
executorService.shutdown();
System.out.println("### Finished submitting tasks and shutdown executorService " + new Date());
executorService.awaitTermination(1, TimeUnit.SECONDS); // try this with 10 seconds and you will see after 3 seconds it reaches next line
// uncomment below and comment out above.
/*new Thread(){
public void run() {
try {
System.out.println("@@@" + new Date());
executorService.awaitTermination(1, TimeUnit.SECONDS); // try this with 10 seconds and you will see after 3 seconds it reaches next line
System.out.println("@@@" + new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();*/
System.out.println("### Finished. " + new Date());
}
private static void testFutureGet() throws InterruptedException, ExecutionException {
List<Future<String>> futuresList = new ArrayList<>();
ExecutorService executorService = Executors.newCachedThreadPool();
ExecutorServiceFutureAndAwaitTermincationExample.CallableTask callableTask1 = new ExecutorServiceFutureAndAwaitTermincationExample.CallableTask(2000, false);
ExecutorServiceFutureAndAwaitTermincationExample.CallableTask callableTask2 = new ExecutorServiceFutureAndAwaitTermincationExample.CallableTask(1000, false);
ExecutorServiceFutureAndAwaitTermincationExample.CallableTask callableTask3 = new ExecutorServiceFutureAndAwaitTermincationExample.CallableTask(3000, false);
System.out.println("### Starting submitting tasks");
// submit the callable and register the returned future object so that it can be processed later.
futuresList.add(executorService.submit(callableTask1));
futuresList.add(executorService.submit(callableTask2));
futuresList.add(executorService.submit(callableTask3));
executorService.shutdown();
System.out.println("### Finished submitting tasks and shutdown executorService");
for (int i = 0; i < futuresList.size(); i++) {
// here "get()" waits for the future tasks to be returned.
System.out.println(futuresList.get(i).get());
}
System.out.println("### Finished.");
}
static class CallableTask implements Callable<String>{
private long timeToSleep;
private boolean shouldLog;
CallableTask(long _timeToSleep, boolean _shouldLog){
this.timeToSleep = _timeToSleep;
this.shouldLog = _shouldLog;
}
@Override
public String call() throws Exception {
String str = new Date() + ": Processing - " + this.hashCode() + " | " + Thread.currentThread() + ", slept for seconds - " + timeToSleep;
System.out.println(str);
Thread.sleep(timeToSleep);
if(this.shouldLog){
System.out.println(str + " ||||| completed at: " + new Date());
}
return str + " ||||| completed at: " + new Date();
}
}
}
和ExecutorService.awaitTermination
并不意味着控制线程(处理您的任务)是否会无限期地运行,线程将一直运行直到它们正在执行的任务完成并且{{1}线程的方法完成完成。我已经解释了上面Future.get(<TimeOut>)
和run
的目的。通常,一个线程中的异常不会影响另一个线程,除非你正在做一些中断/影响其他线程的事情。
答案 2 :(得分:0)
Futire.get
等待任务完成。 ExecutorService.awaitTermination
等待执行程序服务停止。通常,您应该创建Executor
一次并重复使用它直到应用程序关闭。
如果任务未完成,您可能希望使用Fuitire.get
超时然后取消未来。在这种情况下,其他任务不会受到影响:
import java.util.concurrent.*;
public class Test {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(1);
Future task = executor.submit(() -> {
Thread.sleep(200);
return "1";
});
// later in time...
try {
Object result = task.get(150, TimeUnit.MILLISECONDS);
System.out.println("result = " + result);
} catch (InterruptedException e) {
System.out.println("Task interrupted");
} catch (ExecutionException e) {
System.out.println("Task execution failed");
} catch (TimeoutException e) {
System.out.println("Task timed-out. isDone=" + task.isDone() + ", isCancelled=" + task.isCancelled());
// cancel long-running task if you want to save resources
task.cancel(true);
System.out.println("Task Cancelled. isDone=" + task.isDone() + ", isCancelled=" + task.isCancelled());
}
// no more need for executor
System.out.println("Shutting down executor");
executor.shutdown();
}
}
输出:
Task timed-out. isDone=false, isCancelled=false
Task Cancelled. isDone=true, isCancelled=true
Shutting down executor