正确的提交方式并等待ExecutorService的终止

时间:2016-02-10 19:17:57

标签: java multithreading threadpool executorservice

我正在学习如何使用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. 如果我使用ExecutorServiceawaitTermination(),我应该如何等待isTerminated()的终止(有人建议后者是错误的做法) )?

  2. Runnable是否已正确添加到执行程序中,还是应将submit()Future<T>回调一起使用?

  3. 这可能取决于具体情况,所以请您解释(对于这两个问题)我应该何时使用所提到的每个解决方案。

3 个答案:

答案 0 :(得分:1)

实现它的几种方法: (a)在if fraction.numerator == 1: break 内拨打awaitTermination(long someTime, TimeUnit ....)。 (b)将所有可调用的内容存储在Collection对象中并调用while (!executor.isTerminated())。这将等到所有任务由执行者服务完成。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

  

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

  1. 您可以在awaitTermination()之后使用shutdown() OR
  2. 您可以通过传递Runnable / Callable任务列表在执行者服务上使用invokeAll() OR
  3. 您可以使用CountDownLatch
  4. 详细了解相关的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
    3. 如果您使用submit(),则会在框架中隐藏异常,您必须正确处理异常。

      查看相关的SE问题:

      Choose between ExecutorService's submit and ExecutorService's execute

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