【问题标题】:Threads created by Executors.newCacheThreadPool is not daemon though the pool created within a DaemonExecutors.newCacheThreadPool 创建的线程不是守护进程,尽管在守护进程中创建了池
【发布时间】:2018-06-28 06:28:13
【问题描述】:

为了避免将自定义ThreadFactory 传递给ThreadPoolExecutor 以直接使用Executors.newCachedThreadPool();。

我创建了一个线程mainDaemonThread,使用Executors.newCachedThreadPool();,提交任务并在mainDaemonThread 启动之前,我将它设置为daemon,据我所知,一旦父 thread 是一个守护进程,那么它创建的所有线程默认都是daemon。

Daemon Thread

当在某个线程中运行的代码创建新的 Thread 对象时,新线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时,它才是守护线程。

那么为什么Executors.newCachedThreadPool(); 不遵守规则呢?一些与此相关的设计偏好?

import static java.lang.System.out;
public static void main(String... args) throws InterruptedException {
    Thread mainDaemonThread = new Thread(() -> {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(() -> {
            try {
                out.println(Thread.currentThread().isDaemon());
                Thread.sleep(1000);
                out.println(Thread.currentThread().isDaemon());
            } catch(InterruptedException ignored) {
                ignored.printStackTrace();
            }
        });
    });
    mainDaemonThread.setDaemon(true);
    mainDaemonThread.start();
    mainDaemonThread.join();
    out.println(Thread.currentThread().isDaemon());
}

演示的输出:

false
false
false

任何帮助将不胜感激,谢谢~

【问题讨论】:

  • 如果您从守护线程执行新线程,则该规则适用。如果自定义线程工厂介于两者之间,它可能有自己的语义。这就是 API 允许您通过自己的线程工厂来覆盖所有这些规则的原因。

标签: java java-8 daemon executorservice


【解决方案1】:

我想这不是一个正确的答案,但是:

您链接的文档用于Thread 类,并记录了“手动”创建新Thread 的行为。它只是不适用于您提交给ExecutorService 的任务(尽管我知道您为什么会这样)。

如果您查看源代码,newCachedThreadPool 执行程序使用(内部)DefaultThreadFactory,它显式创建了一个非守护进程 Thread:

public Thread newThread(Runnable r) {
    Thread t = new Thread(group, r,
                          namePrefix + threadNumber.getAndIncrement(),
                          0);
    if (t.isDaemon())
        t.setDaemon(false); // ta-da
    if (t.getPriority() != Thread.NORM_PRIORITY)
        t.setPriority(Thread.NORM_PRIORITY);
    return t;
}

如果您希望执行程序创建一个守护线程,您可以将Executors#newCachedThreadPool(ThreadFactory) 方法与创建守护进程Threads 的工厂一起使用。由于ThreadFactory是函数式接口,所以就这么简单

Executors#newCachedThreadPool(Thread::new);

【讨论】:

  • 感谢您的澄清。但我仍然想知道为什么DefaultThreadFactory 会重置daemon 和priority。这是一种protective 机制来确保开发人员真正了解他/她将要做什么?
  • @Hearen 好吧,我只能给出一个有根据的猜测。如果守护线程没有终止,它不会阻止关闭。当执行程序启动一个线程时,该线程被认为是一个需要完成的工作线程,无论是否由守护进程启动。
  • @daniu 举一个反例,默认情况下,Fork/Join 池只创建守护线程。但是这些线程池的共同点是策略是一致的,并且不依赖于工作线程的创建者,因为创建者是不可预测的。当队列已满且未达到最大计数时,每个提交作业的线程可能是工作线程的创建者。如果提交者线程具有不同的属性,则工作线程的属性不应变得不可预测。这是一个可以理解的想法。
猜你喜欢
  • 2013-07-31
  • 1970-01-01
  • 2016-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
  • 2014-04-12
相关资源
最近更新 更多