我想知道实现多个生产者的最佳机制是什么 - 单个消费者场景,我必须保持当前未处理请求的数量是最新的。
我的第一个想法是使用ConcurrentLinkedQueue:
public class SomeQueueAbstraction {
private Queue<SomeObject> concurrentQueue = new ConcurrentLinkedQueue<>();
private int size;
public void add(Object request) {
SomeObject object = convertIncomingRequest(request);
concurrentQueue.add(object);
size++;
}
public SomeObject getHead() {
SomeObject object = concurrentQueue.poll();
size--;
}
// other methods
问题在于我必须在add
和size ++
以及poll
和size--
上明确同步,才能始终保持准确{{1}这使得size
开始时毫无意义。
在保持数据一致性的同时,实现尽可能好的性能的最佳方法是什么?
我应该使用ConccurentLinkedQueue
代替显式同步还是有更好的方法来实现这一目标?
这里有类似的问题/答案:
java.util.ConcurrentLinkedQueue
讨论ArrayDequeue
上的复合操作如何自然不是原子的,但没有直接的答案,给定场景的最佳选择是什么。
注意:我正在明确计算大小,因为固有的.size()方法的时间复杂度为O(n)。
注意2:我也担心我没有明确写过的getSize()方法会增加更多的争用开销。可以相对频繁地调用它。
我正在寻找处理多个生产者的最有效方法 - 单个使用频繁的getSize()调用的消费者。
替代建议:如果SomeObject结构中有elementId,我可以从ConcurrentLinkedQueue.poll()获得当前大小,并且只需要在机制内完成锁定以生成这样的id。现在可以正确使用添加和获取而无需额外锁定。这种票价如何作为替代品呢?
答案 0 :(得分:1)
您可以使用显式锁定,这意味着您可能不需要并发队列。
public class SomeQueueAbstraction {
private Queue<SomeObject> queue = new LinkedList<>();
private volatile int size;
private Object lock = new Object();
public void add(Object request) {
SomeObject object = convertIncomingRequest(request);
synchronized(lock) {
queue.add(object);
size++;
}
}
public SomeObject getHead() {
SomeObject object = null;
synchronized(lock) {
object = queue.poll();
size--;
}
return object;
}
public int getSize() {
synchronized(lock) {
return size;
}
}
// other methods
}
这样,就可以安全地在队列中添加/删除元素并更新size
。
答案 1 :(得分:1)
因此要求是报告最新的当前未处理请求数。这经常被要求确实使ConcurrentLinkedQueue.size()
不合适。
这可以使用AtomicInteger来完成:它很快,并且总是尽可能接近当前未处理的请求数。
以下是一个示例,请注意一些小更新,以确保报告的大小准确无误:
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class SomeQueueAbstraction {
private final Queue<SomeObject> concurrentQueue = new ConcurrentLinkedQueue<>();
private final AtomicInteger size = new AtomicInteger();
public boolean add(Object request) {
SomeObject object = convertIncomingRequest(request);
if (concurrentQueue.add(object)) {
size.incrementAndGet();
return true;
}
return false;
}
public SomeObject remove() {
SomeObject object = concurrentQueue.poll();
if (object != null) {
size.decrementAndGet();
}
return object;
}
public int getSize() { return size.get(); }
private SomeObject convertIncomingRequest(Object request) {
return new SomeObject(getSize());
}
class SomeObject {
int id;
SomeObject(int id) { this.id = id; }
}
}