Почему метод execute () класса ExecutorService, возвращенного из служебного класса Executors, не может завершиться естественным образом - PullRequest
0 голосов
/ 08 июня 2018

Как мы знаем, java.util.concurrent.Executors содержит много методов, таких как

  • newCachedThreadPool
  • newFixedThreadPool
  • newScheduledThreadPool
  • newSingleThreadExecutor
  • newSingleThreadScheduledExecutor

    Они возвращают ExecutorService, который содержит метод execute(Runnable task).Однако при вызове execute(Runnable task) из ExecutorService, возвращенного из вышеупомянутых фабричных методов , он может завершиться только путем вызова shutdown() или shutdownNow()

Например, если мы добавим следующий код в метод main,

ExecutorService e = Executors.newSingleThreadExecutor();
e.execute(() -> system.out.println("test")); 

, то вызов основной программы никогда не прекратится, поскольку shutdown() или shutdownNow() не вызывается.Таким образом, программа, содержащая следующий фрагмент в main , прекратит работу

ExecutorService e = Executors.newSingleThreadExecutor();
e.execute(() -> system.out.println("test"));
e.shutdown();

Однако некоторые подклассы ExecutorService, такие как возвращаемый при вызове Executors.newWorkStealingPool или ForkJoinPool, могутзавершить работу без вызова shutdown() или shutdownNow()

Итак, мой ВОПРОС : почему execute() из ExecutorService возвращается из вышеупомянутых фабричных методов начинаться с "new" не завершается без вызова shutdown() или shutdownNow() с точки зрения дизайна?

Ответы [ 2 ]

0 голосов
/ 09 июня 2018

Кратко о потоках Java: существует два типа потоков - демон и не демон.Программа завершается, когда все ее потоки, не являющиеся демонами, завершили выполнение.Потоки демона могут работать только до тех пор, пока работает программа, и не блокируют завершение, например, сборщик мусора .Когда java-программа запускает все свои потоки, кроме основного, они являются демонами.

newSingleThreadExecutor() и его defaultThreadFactory() создают потоки, не являющиеся демонами.Что имеет смысл - вы создаете пул потоков , которые ждут работы, и вы должны явно отключить ее.

ForkJoinPool, с другой стороны, абстрагирует васиз основного пула потоков.Таким образом, он может использовать потоки демона, поскольку в любом случае вы намерены ждать выполнения задачи.

0 голосов
/ 09 июня 2018

Руи, ответ, почему твой пример зависает, прост.По умолчанию потоки в ExecutorService являются потоками, не являющимися демонами, и Java-программа не завершит работу, если запущены потоки, не являющиеся демонами.Если вам не нужно это поведение, все, что вам нужно сделать, это определить ThreadFactory, который создает потоки демона, например:

public class Test {
    static ThreadFactory mThreadFactory = new ThreadFactory() {
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setDaemon(true);
            return t;
        }
    };

    public static void main(String[] args) {
        ExecutorService e = Executors.newSingleThreadExecutor(mThreadFactory);
        e.execute(new Runnable() { public void run() { System.out.println("test"); } });
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...