【问题标题】:Correct way to submit to and wait for termination of an ExecutorService提交并等待 ExecutorService 终止的正确方法
【发布时间】:2016-02-10 19:17:56
【问题描述】:

我正在学习如何使用 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");
    }
}

我有两个问题:

  1. 我应该如何等待ExecutorService的终止,我应该使用awaitTermination()还是isTerminated()(有人建议后者是错误的做法)?

  2. Runnables 是否正确添加到执行程序中,还是应该将submit()Future&lt;T&gt; 回调一起使用?

这可能取决于上下文,所以请您解释一下(对于这两个问题)我应该什么时候使用提到的每个解决方案。

【问题讨论】:

  • 您可以同时使用awaitTermination() 等待(它可以抛出一个InterruptedException),然后在catch 块中使用isTerminated() 来检查是否成功终止。当您想知道单个任务是否已被处理时,使用 Future 回调。

标签: java multithreading threadpool executorservice


【解决方案1】:

实现它的几种方法: (a) 在while (!executor.isTerminated()) 内致电awaitTermination(long someTime, TimeUnit ....)。 (b) 将所有可调用对象存储在 Collection 对象中并调用executor.invokeAll(....)。这将等到执行器服务完成所有任务。

【讨论】:

    【解决方案2】:

    这个程序没有等待线程终止,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
    

    【讨论】:

      【解决方案3】:

      1.我应该如何等待ExecutorService的终止,我应该使用awaitTermination()还是isTerminated()(有人建议后者是错误的方法)?

      1. 您可以在shutdown() 之后使用awaitTermination()
      2. 您可以通过传递可运行/可调用任务列表在执行程序服务上使用invokeAll()
      3. 您可以使用CountDownLatch

      查看相关的 SE 问题了解更多详情:

      How to wait for all threads to finish, using ExecutorService?

      ExecutorService, how to wait for all tasks to finish

      Waiting for all the threads to finish before shutting down the Executors

      2.Runnables 是否正确添加到执行程序中,还是应该将 submit() 与 Future 回调一起使用?

      1. 如果您只想运行命令而不等待结果,请使用Runnable
      2. 如果要查看任务执行后的结果,请使用Callable

      如果您使用submit(),异常会隐藏在框架中,您必须注意正确处理异常。

      查看相关的 SE 问题:

      Choose between ExecutorService's submit and ExecutorService's execute

      difference between executor.submit and executor.execute in this code in Java?

      【讨论】:

        猜你喜欢
        • 2015-10-30
        • 1970-01-01
        • 2011-06-24
        • 1970-01-01
        • 2015-11-30
        • 2014-11-18
        • 1970-01-01
        • 2010-09-24
        相关资源
        最近更新 更多