更新:我已根据下面的正确答案更新了代码。这有效,但会产生一个新问题(我将发布一个新问题)。
使用具有多个生产者和消费者的信号量创建一个阻塞有界缓冲类。
目标是使用原子整数作为指针,因此我不必在内部进行同步。溢流处理已更正为现在使用CAS。
但是这不起作用,除非我在AtomicInteger指针周围使用synchronized(参见下面的评论)。 不确定原因?滚动到下方,看看“缺少参赛作品”是什么意思......
public class BoundedBuffer<T> {
private static final int BUFFER_SIZE = Short.MAX_VALUE+1;
private AtomicReferenceArray<T> m_buffer = null;
private Semaphore m_full = new Semaphore(BUFFER_SIZE);
private Semaphore m_empty = new Semaphore(0);
private AtomicInteger m_writePointer = new AtomicInteger();
private AtomicInteger m_readPointer = new AtomicInteger();
public BoundedBuffer() {
m_buffer = new AtomicReferenceArray<T>(BUFFER_SIZE);
}
public static int safeGetAndIncrement(AtomicInteger i) {
int oldValue = 0, newValue = 0;
do {
oldValue = i.get();
newValue = (oldValue == Short.MAX_VALUE) ? 0 : (oldValue + 1);
} while (!i.compareAndSet(oldValue, newValue));
return oldValue;
}
public void add(T data) throws InterruptedException {
m_full.acquire();
synchronized (this) { // << Commenting this doesn't work
// CAS-based overflow handling
m_buffer.set(safeGetAndIncrement(m_writePointer),data);
}
m_empty.release();
}
public T get() throws InterruptedException {
T data = null;
m_empty.acquire();
synchronized (this) { // << Commenting this doesn't work
// CAS-based overflow handling
data = m_buffer.get(safeGetAndIncrement(m_readPointer));
}
m_full.release();
return data;
}
}
测试程序有......
8个生产者线程,每个都将大约10000个条目放入队列。 每个条目都是一个格式的字符串:A“:”B 哪里 A是8个线程的数字0..7。 B只是从0..9999起数字增加的数量
4个消费者线程,消耗所有内容,直到命中null。
一旦生产者线程完成了将所有内容添加到缓冲区中,就会将4个null添加到队列中(以阻止使用者)。
线程输出......
P:数据,1:9654 @ 1 P:数据,5:1097 @ 347 C:数据,1:9654 @ 1 P:数据,4:5538 @ 1 C:数据,4:5538 @ 1 C:数据,null @ 14466
验证 在验证所有生成的条目是否都是消费者时,会有一些条目丢失(就在敲击arrayindexoutofbounds之前(可能只是巧合)。
...验证 失踪4:5537 失踪5:1096 验证
答案 0 :(得分:2)
递增计数器时需要处理溢出。例如,您可以使用以下方法代替getAndIncrement()
:
public static int safeGetAndIncrement(AtomicInteger i) {
int oldValue = 0;
do {
oldValue = i.get();
int newValue = (oldValue == MAX_VALUE) ? 0 : (oldValue + 1);
} while (!i.compareAndSet(oldValue, newValue));
return oldValue;
}
它使用典型的compare-and-swap方法,不应该损害性能,因为getAndIncrement()
在内部以相同的方式实现。
此外,如果MAX_VALUE
为BUFFER_SIZE
,则您不需要% BUFFER_SIZE
操作。