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



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

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

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

如果要遍历 ThreadPoolExecutor 使用的 workQueue,您会怎么做?还是有替代方法?

这是..为生产者使用者问题的变体选择数据结构

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

您可以重写 beforeExecute 和 afterExecute 方法,让您知道任务已开始和完成。您可以覆盖 execute() 以了解何时添加任务。

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

顺便说一句:队列是线程安全的,但不能保证你会看到每个条目。

ConcurrentLinkedQueue.iterator() 被记录为

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

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

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

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

然后我有自己的问题。 我看到的问题是,当您执行"可运行"时,"可运行"没有放在队列中,而是放在 FutureTask "包装器"中,我找不到任何方法来确定我正在查看的哪一个可运行项。 因此,抓取和检查队列是毫无用处的。 有人知道我错过了那里吗?

如果您遵循 Jon Skeet 在上一个问题的已接受答案中的建议,那么您将通过锁控制对队列的访问。如果在正在进行的队列上获取锁,则可以保证遍历不会错过其中的任何项目。

当然,这样做的问题在于,当您执行遍历时,队列上的所有其他操作(其他生产者和使用者尝试访问它)都将阻塞,这可能会对性能产生非常可怕的影响。

相关内容

  • 没有找到相关文章

最新更新