短版本 - 我正在寻找最有效的方法将两个队列包装成一个用于线程池,其中优先级给予其中一个队列的内容,只要它是非空的然后下降回到第二个队列。
长版: 系统中的几个线程池,每个线程池都有自己的队列。
“外部”请求来自外部并被提交到其中一个池处理一段时间,然后转移到另一个队列。在第一次转移后,请求被视为“内部”,直到完成为止。请求可以在所有线程池之间传输,并且可能最终在它开始的那个中。
我想要做的是,如果每个线程池的队列包含内部请求,则应首先处理它们,直到队列用完内部请求,然后它应切换到外部请求。如果显示新的内部,则应该接下来处理。
不需要纯FIFO,目前每个线程池使用一个LinkedTransferQueue,因为这是我在许多消费者和许多生产者中发现的最快的FIFO队列。非常高的插入率和LinkedTransferQueue中的自旋锁效果非常好。
队列的大小在其他地方处理(因为拒绝),所以我真的只需要正确的投放/接受行为。
过去尝试过无法解决的解决方案:
关于解决方案的想法:
不能只在外部做一个peek(),而在内部是if null,因为有些东西可能被插入到External中,我将被阻塞等待内部。我永远不会从内部取消阻止,因为除非我从外部处理它们,否则事物不会在内部结束...如果我将它旋转180度(除非它来自系统内部),同样的方式
我对一篇毫无意义的帖子道歉......
答案 0 :(得分:0)
尝试了另一种方法,一个队列提供另一个队列,当有太多“内部”请求被处理时阻塞...锁定性能减半。
最后我最终做到了这一点: 将两个LinkedTransferQueues放在实现BlockingQueue的类中。 让“offer”方法决定最终的队列,take方法执行以下操作(不是确切的代码):
@Override
public Runnable take() throws InterruptedException {
int c = 0;
ThreadLocalRandom rand = ThreadLocalRandom.current();
while (true) {
// Check internal first
Runnable r = internalQueue.poll();
if (r != null) {
return r;
}
// Spin for a while on external, with occasional yield.
while(c < 128)
{
r = externalQueue.poll();
if (r != null) {
return r;
}
if(rand.nextInt(32) == 0)
{
Thread.yield();
}
c++;
}
// Use the transfer queues time limited poll.
r = externalQueue.poll(10000, TimeUnit.NANOSECONDS);
if (r != null) {
return r;
}
}
}
信不信由你,这实际上将吞吐量提高了15%,并将延迟减少了一半。较少的“已启动但未完成”请求占用资源,并且可能在队列中的争用较少(由于我的使用场景)。
自旋锁的值和想法取自LinkedTransferQueue的代码。
缺点是,使用上面的代码,系统空闲率为11%,但通过在30秒不活动后增加轮询超时可以轻松解决这个问题。
如果有人碰巧碰到某一天,仍然欢迎更好的解决方案,但现在这种方法很有效。