当前位置: 首页 > 面试题库 >

核心队列大小为0的ThreadPoolExecutor在任务队列已满之前不应执行任务

吕皓
2023-03-14
问题内容

我正在学习 Java Concurrency in Practice, 并陷入了 8.3.1线程创建和拆除的
主题。以下脚注警告要保持corePoolSize为零。

有时,开发人员倾向于将核心大小设置为零,以使工作线程最终被拆除,因此不会阻止JVM退出,但这会在不使用a的线程池中引起一些奇怪的现象。他们的工作队列使用SynchronousQueue(就像newCachedThreadPool一样)。
如果池已经达到核心大小,则ThreadPoolExecutor仅在工作队列已满时才创建新线程。
因此,提交给具有任何容量且核心大小为零的工作队列的线程池的任务要等到队列填满后才能执行
,这通常是不希望的。

因此,为了验证这一点,我编写了此程序,但该程序无法如上所述运行。

    final int corePoolSize = 0;
    ThreadPoolExecutor tp = new ThreadPoolExecutor(corePoolSize, 1, 5, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>());

    // If the pool is already at the core size
    if (tp.getPoolSize() == corePoolSize) {
        ExecutorService ex = tp;

        // So tasks submitted to a thread pool with a work queue that has any capacity
        // and a core size of zero will not execute until the queue fills up.
        // So, this should not execute until queue fills up.
        ex.execute(() -> System.out.println("Hello"));
    }

输出你好

因此,程序的行为是否建议ThreadPoolExecutor如果提交任务而与无关地创建至少一个线程corePoolSize=0。如果是,那么教科书中的警告是什么。

编辑:@SK 的建议下,对 jdk1.5.0_22中 的代码进行了以下更改测试:

ThreadPoolExecutor tp = new ThreadPoolExecutor(corePoolSize, 1, 5, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(1));//Queue size is set to 1.

但是,有了此更改,程序将终止而不打印任何输出。

那么我会从书中误解这些陈述吗?

编辑(@sjlee): 很难在注释中添加代码,因此我将其添加为编辑内容…您可以尝试此修改并针对最新的JDK和JDK 1.5运行它吗?

final int corePoolSize = 0;
ThreadPoolExecutor tp = new ThreadPoolExecutor(corePoolSize, 1, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<>());

// If the pool is already at the core size
if (tp.getPoolSize() == corePoolSize) {
    ExecutorService ex = tp;

    // So tasks submitted to a thread pool with a work queue that has any capacity
    // and a core size of zero will not execute until the queue fills up.
    // So, this should not execute until queue fills up.
    ex.execute(() -> System.out.println("Hello"));
}
tp.shutdown();
if (tp.awaitTermination(1, TimeUnit.SECONDS)) {
    System.out.println("thread pool shut down. exiting.");
} else {
    System.out.println("shutdown timed out. exiting.");
}

@sjlee已在评论中发布了结果。


问题答案:

ThreadPoolExecutor在Java 5中,当核心池大小为零时,这种奇怪的行为显然被认为是一个错误,并且在Java 6中已悄然修复。

实际上,由于在6至7之间进行了一些代码修改,该问题在Java 7中再次出现。然后,该问题被报告为错误,被确认为错误并已解决。

无论哪种方式,都不应使用受此错误影响的Java版本。Java 5于2015年停产,并且Java 6及更高版本的最新可用版本不受影响。“
Java并发实践”中的该部分不再合适。

参考文献:

  • http://cs.oswego.edu/pipermail/concurrency-interest/2006-December/003453.html (阅读整个主题)
  • http://gee.cs.oswego.edu/dl/concurrency-interest/index.html(请参阅ThreadPoolExecutorJSR166y捆绑包中的版本。)
  • https://bugs.openjdk.java.net/browse/JDK-7091003)


 类似资料:
  • 我在练习Java并发性时,被困在了8.3.1线程创建和拆卸主题上。下面的脚注警告要将corePoolSize保持为零。 开发人员有时会倾向于将核心大小设置为零,这样工作线程最终会被拆除,因此不会阻止JVM退出,但这可能会在不使用同步队列的线程池中导致一些看似奇怪的行为。工作队列(如newCachedThreadPool所做的那样)。如果池已经达到核心大小,则ThreadPoolExector仅在工

  • 我需要能够更改ThreadPoolExecator的任务队列的大小。当然,BlockingQueue不支持更改大小,ThreadPoolExecitor不支持更改队列。 所以,我想到的方法是使用ThreadPoolExecutor。shutdownNow(),它返回了一个尚未执行的可运行程序列表。然后,我可以创建一个具有所需队列大小的新执行器,并重新提交所有任务。 问题是在shutdownNow(

  • 问题内容: 我对ThreadPoolExecutor有一个非常简单的问题。我有以下情况:我必须使用队列中的对象,为它们创建适当的工作程序任务,然后将其提交给ThreadPoolExecutor。这很简单。但是在关闭情况下, 许多 工作人员可能会排队等待执行。由于这些任务之一可能正在运行一个小时,而且我希望相对快速地正常关闭应用程序,因此我想从ThreadPoolExecutor中丢弃所有排队的任务

  • 我找不到任何符合我要求的遗嘱执行人。我想要一个具有corePoolSize、maximumPoolSize和BlockingQueue的ExecutorService; 当执行函数被调用时,像往常一样,使用核心线程,如果核心线程正在使用,则将任务放入队列,如果队列已满,则创建新线程,直到达到最大池大小。这是ThreaPoolExecator的标准行为。线程池执行器 在这部分之前一切都好。我可以使用

  • 如果正在运行的线程少于corePoolSize线程,则执行器宁愿添加一个新线程,而不是排队。2)如果corePoolSize或更多线程正在运行,则执行器更喜欢将请求排队,而不是添加新线程。 如果请求无法排队,将创建一个新线程,除非该线程将超过maximumPoolSize,在这种情况下,任务将被拒绝。 第一种情况是可以的,但我想要的是,当核心线程被利用时,任务不需要排队(即使在有界队列的情况下,比

  • 我想了解在fork-连接池中处理任务Java顺序。 到目前为止,我在文档中找到的唯一相关信息是关于一个名为“asyncMode”的参数,该参数“如果此池对从未加入的分叉任务使用本地先进先出调度模式,则为真”。 我对这句话的解释是,每个工人都有自己的任务队列;工人从他们自己队列的前面接受任务,或者如果他们自己的队列是空的,从其他工人队列的后面偷走任务;如果asyncMode为真(分别为假),工作人员