Java的ExecutorService.awaitTermination与Future.get(<timeout>)

时间:2017-05-08 18:35:19

标签: java concurrency java.util.concurrent

我正在使用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) {
    }

3 个答案:

答案 0 :(得分:1)

  

你能告诉我使用ExecutorService.awaitTermination和使用Future.get()有什么区别吗?

只应在ExecutorService.awaitTermination()请求后调用{p> ExecutorService.shutdown()。如果在关闭之前调用awaitTermination,则规范不会定义行为。但简而言之,只有在您打算丢弃ExecutorService并且再也不使用它时,才应使用awaitTermination。 Java EE Con​​currency规范实际上拒绝调用此方法的应用程序。总的来说,这看起来不是您的用例的正确选项。

Future.get(Timeout)用于等待特定Future完成,与想要关闭未来正在运行的ExecutorService无关。

也相关,请看这个答案:
How to check if all tasks running on ExecutorService are completed

答案 1 :(得分:1)

ExecutorService.awaitTerminationFuture.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