如何以线程安全的方式访问ThreadpoolExecutor的底层队列

时间:2011-05-09 10:16:38

标签: java executors

getQueue()方法提供对ThreadPoolExecutor中底层阻塞队列的访问,但这似乎不安全。

对此函数返回的队列进行遍历可能会错过ThreadPoolExecutor对队列所做的更新。

“方法getQueue()允许访问工作队列以进行监视和调试。强烈建议不要将此方法用于任何其他目的。”

如果你想遍历ThreadPoolExecutor使用的workQueue,你会怎么做?或者有其他方法吗?

这是...的延续 Choosing a data structure for a variant of producer consumer problem

现在,我正在尝试多个生产者多个使用者,但是我想使用一些现有的线程池,因为我不想自己管理线程池,而且当ThreadPoolExecutor完成执行某些任务时我还想要一个回调能够以线程安全的方式检查“inprogress事务”数据结构。

3 个答案:

答案 0 :(得分:1)

您可以覆盖beforeExecute和afterExecute方法,以通知您任务已启动和完成。您可以覆盖execute()以了解何时添加任务。

您遇到的问题是Queue不是为查询而设计的,任务可以在您看到之前使用。解决此问题的一种方法是创建自己的队列实现(可能覆盖/包装ConcurrentLinkedQueue)

BTW:队列是线程安全的,但不保证你会看到每个条目。

ConcurrentLinkedQueue.iterator()记录为

  

以适当的顺序返回此队列中元素的迭代器。返回的迭代器是一个“弱一致”的迭代器,它永远不会抛出ConcurrentModificationException,并保证遍历构造迭代器时存在的元素,并且可能(但不保证)反映构造之后的任何修改。

答案 1 :(得分:1)

如果您希望复制队列中的项目并确保队列中的内容尚未执行,您可以尝试这样做:

a)介绍暂停和恢复执行的能力。请参阅:http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html

b)首先暂停队列,然后复制队列,然后恢复队列。

然后我有自己的问题。我看到的问题是,当你执行你的“Runnable”时,“Runnable”没有放在队列中,而是一个FutureTask“包装器”,我找不到任何方法来确定我正在寻找哪一个我的runnables在。因此,抓住并检查队列是没有用的。有人知道我错过了吗?

答案 2 :(得分:0)

如果您在前一个问题的accepted answer中关注Jon Skeet的建议,那么您将通过锁控制对您的队列的访问。如果您在正在进行的队列中获得锁定,那么您可以保证遍历不会遗漏任何项目。

当然,问题在于,当你正在遍历队列上的所有其他操作(其他生产者和消费者试图访问它)时,会阻塞,这可能会对性能产生非常可怕的影响。