【问题标题】:Allowing core thread timeout with ScheduledThreadPoolExecutor使用 ScheduledThreadPoolExecutor 允许核心线程超时
【发布时间】:2018-07-03 14:38:00
【问题描述】:

你能解释一下,为什么ScheduledThreadPoolExecutorjavadoc 是这样的:

此外,将corePoolSize 设置为 零或使用allowCoreThreadTimeOut,因为这可能会离开池 线程在它们有资格运行时处理任务。

我试图分析当必须执行新任务时如何在这个线程池中创建新线程,我认为 javadoc 中描述的问题不应该发生。

【问题讨论】:

  • 什么意思不应该发生?
  • 调用execute方法时,调用的是ensurePrestart,如果worker数量小于核心池大小,则添加worker。所以,不可能出现线程池中没有线程导致任务没有执行的情况。

标签: java multithreading threadpoolexecutor


【解决方案1】:

线程池尽量使工作线程数等于corePoolSize,通过缓存线程来提高效率。允许核心线程超时与此目的背道而驰。如果允许核心线程超时,新任务会被执行,但会导致重复创建和销毁工作线程。

如果设置allowCoreThreadTimeOut = true,那么当工作线程在任务队列中找不到任务并超时后,即使工作线程数少于corePoolSize,它们也会被销毁。所以,如果此时提交新任务,线程池就得创建新线程了。

如果设置allowCoreThreadTimeOut = false,那么当工作线程在任务队列中找不到任务并且工作线程数少于corePoolSize后,它们不会被销毁,一直等待新的任务。

【讨论】:

    【解决方案2】:

    我的猜测是大多数情况下答案是陈旧的 Javadoc。正如您所注意到的,ensurePrestart 确保只要corePoolSize > 0,调用后核心池线程的数量就非零。从https://github.com/openjdk/jdk/commit/2d19ea519b17529a083a62eb219da532693bbef3 开始就是这种情况,但值得注意的是,提交并没有更新ScheduledThreadPoolExecutor 上的Javadoc。

    但是,细节也不是那么简单。您不仅要担心新任务提交和完成后任务重新安排,还需要担心核心池线程空闲,因为所有计划任务都在未来太远,无法在池超时之前触发。

    不确定我是否正确读取了 JRE 代码,但看起来在这种情况下,池将:

    1. 启动一个工作线程(由于ensurePrestart
    2. 无论线程类型(核心与否),线程都有资格超时,因为allowCoreThreadTimeout 为真
    3. 工作线程轮询 DelayedWorkQueue 以获取下一个任务,超时
    4. 轮询返回null(超时),因为下一个计划任务超出池超时时间
    5. 核心线程会因为认为无事可做而终止
    6. ThreadPoolExecutor.processWorkerExit 将在工作人员终止时运行。它将检查队列,注意到它是非空的,因此至少需要至少一个线程
    7. 如果被终止的线程是最后一个线程,它会注意到没有达到最小值并立即启动一个新的(非核心)worker
    8. 从第 1 步开始重复

    所以,池按您的意愿工作,但可能也不会处于理想状态(您真的希望单核线程轮询没有超时,而不是线程不断旋转,轮询超时,超时,然后启动一个新线程来替换自己)。从这个意义上说,第 6 步确实阻止了 Javadoc 中提到的情况(当任务符合条件时,所有池线程都已超时),但由于不必要的线程创建/销毁循环,它并不完美。

    这种奇怪之处实际上是因为DelayedWorkQueue 在语义上违反了BlockingQueue 合约。在其他条件相同的情况下,您会假设 size() > 0 意味着后续的 poll(...) 将成功检索一个元素并且不会超时,但 DelayedWorkQueue 允许这些元素保留一段时间(即使它们已经通过size()isEmpty() 可见)。

    注意:似乎这段代码在 Java 8 中发生了变化,在ThreadPoolExecutor.getTask() 中添加了this condition。这将使最后一个工作线程保持活动状态并避免线程创建/销毁循环,但它将忙于轮询工作队列以进行工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-08
      • 2019-06-04
      • 1970-01-01
      • 2011-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多