我发现自己重复了这种模式,并且经常想知道它是否在Java中是惯用的,还是有更好的方法来实现这种行为。
问题:给定生产者/消费者设置,消费者希望处理一批商品,因此它使用drainTo()
,但是drainTo()
会轮询现有商品,并且可能无法获取任何商品,为避免这种情况,我在排水口前面加上了前缀take()
以确保其阻塞,直到至少一项可用。
对于特定的数据集,我遇到的一个问题是在许多用例中,批处理大小通常是(1,N,1,N)之间不规则的交替。通常,这是解决此问题的常用方法:
例:
ArrayBlockingQueue<Foo> queue;
function void produce() {
while(true) {
queue.put(createFoo());
}
}
function void consumeBatchSpin() {
while(true) {
List<Foo> batch = Lists.newLinkedList();
queue.drainTo(batch);
doSomething(batch);
//the problem here is that if nothing is being produced, this loop will spin
}
}
function void consumeBatchTake() {
while(true) {
List<Foo> batch = Lists.newLinkedList();
batch.add(queue.take()); //force at least one item to be there
queue.drainTo(batch);
doSomething(batch);
}
}
最佳答案
您是否考虑过添加到列表中并在获取时使用整个列表。
我最近发布了一个here。它正在接受代码审查here,但我的测试表明它很健壮。
本质上,执行卖权时,您会将新元素添加到当前列表中。当您获取时,您将获得整个列表,并用一个新的空列表原子地替换它。
无需使用drainTo
,也无需旋转。