java doc上的ThreadPoolExecutor

时间:2011-02-28 17:08:24

标签: java multithreading

http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html 你可以阅读构造函数的参数描述。 特别是在“核心和最大池大小”段落中,写了:

  

如果有超过corePoolSize但运行的maximumPoolSize线程少于,则只有在队列已满时才会创建新线程。

...

  

通过将maximumPoolSize设置为基本无限制的值(例如Integer.MAX_VALUE),您可以允许池容纳任意数量的并发任务。

现在我无法理解“只有队列满了”的第一部分代表...... ThreadPoolExecutor会等到队列满了还是只创建一个新工作者?

现在假设我们之间有更多不同步的任务:使用ThreadPoolExecutor可能会导致死锁?假设我的前10个任务是生产者并且CorePoolSize是10,那么成功的消费者任务将进入队列并且在队列满之前不会运行?如果是这样,这种行为可能会导致死锁,因为前10个生产者可以继续等待,暂停Core的所有10个线程。 队列满了? 我不确定我是否理解文档,因为Executors.newCachedThreadPool()似乎在达到maxPoolSize之前创建一个新的Worker,然后它将任务发送到队列。 我有点困惑。

谢谢

2 个答案:

答案 0 :(得分:2)

构造ThreadPoolExecutor时,传入一个名为BlockingQueue<Runnable>的{​​{1}}实例,以保存任务,并且正在引用此队列。

事实上,名为“排队”的文档部分详细介绍了您对此感到困惑的短语:

  

任何BlockingQueue都可用于转移和保留提交的任务。此队列的使用与池大小调整相互作用:

     
      
  • 如果运行的corePoolSize线程少于,则执行程序总是更喜欢添加新线程而不是排队。
  •   
  • 如果corePoolSize或更多线程正在运行,则Executor总是更喜欢排队请求而不是添加新线程。
  •   
  • 如果请求无法排队,则会创建一个新线程,除非这会超过maximumPoolSize,在这种情况下,该任务将被拒绝。
  •   

关于你的第二部分,关于任务间依赖关系 - 在这种情况下,我认为将它们放入所有的ExecutorService 并不是一个好主意。 ExecutorService适合在将来的某个时刻运行一个自包含的代码,但是通过设计它并不意味着确定何时发生这种情况,除了“在(希望接近)未来的某个方便点,之前排队的任务已经开始。“

将这种缺乏计时精度与并发操作所施加的硬排序要求结合起来,你可以看到让生产者和消费者需要相互交谈,放入通用的ExecutorService,是一个秘诀。对于非常烦人和令人困惑的错误。

,我相信你可以通过充分的参数调整来实现它。然而,它不清楚为什么它工作,不清楚依赖是什么,并且(而不是如果)它破坏时,它将是非常难以诊断。 (我怀疑比正常的并发问题更难)。最重要的是,ExecutorService不是为了运行具有硬时序限制的Runnables而设计的,所以甚至可以通过新版本的Java来解决这个问题,因为它不会像这样工作。

我认为你提出错误的问题,通过查看详细信息,或许你的概念有点不稳定。也许如果你解释了你想要达到的目标,就会有更好的方法来实现它。

答案 1 :(得分:0)

澄清你的第一句话 - 如果执行者已经有corePoolSize个线程在运行,并且所有这些线程在提交新任务时都很忙,它将创建更多线程,但会将任务排入队列,直到其中一个线程变为空闲。它只会在队列变满时创建一个新线程(最多maxPoolSize限制)。如果队列很大(即仅受内存约束限制),那么将不会创建超过corePoolSize个线程。

Executors.newCachedThreadPool()将创建一个零大小队列的执行程序,因此队列始终已满。这意味着一旦提交任务,它将创建一个新线程(或重新使用空闲线程)。因此,它不能很好地证明核心/最大/队列参数的用途。