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 在上一个问题的已接受答案中的建议,那么您将通过锁控制对队列的访问。如果在正在进行的队列上获取锁,则可以保证遍历不会错过其中的任何项目。
当然,这样做的问题在于,当您执行遍历时,队列上的所有其他操作(其他生产者和使用者尝试访问它)都将阻塞,这可能会对性能产生非常可怕的影响。