我正在尝试构建的有界缓冲类的属性...
现在问题......
问题:我似乎无法在下面的代码中注释掉 synchronized(this)blocks 。我认为使用AtomicInteger作为指针的重点是避免这样做。
注释掉synchronized(this)会阻止消费者丢失一些生产者放入的项目。如果我包含synchronized(this)块,那么一切都很好,并且生成的每一件东西都被消耗掉了。
我错过了什么?
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;
}
}
答案 0 :(得分:1)
可能存在这样的问题:当删除同步块时,数组中的get()不是原子的增量。我推测的破坏场景要求生产者超越消费者,然后你可以让生产者覆盖尚未读取的数组条目,如果信号量释放是由无序读取触发的。
考虑缓冲区已满(写入器索引为N,读取器索引为N + 1)并且2个线程正在尝试从缓冲区读取的情况。 (为简单起见,假设N不接近环绕点。)
线程1接收索引N + 1,从中读取其项目。
线程2接收索引N + 2,从中读取其项目。
由于调度的棘手,线程2首先从缓冲区数组获取并在线程1从数组中获取其项之前释放m_full
信号量。
线程3(生产者)唤醒并将一个项目写入缓冲区中的下一个可用插槽N + 1,同样在线程1从缓冲区读取之前。
线程1然后获取索引N + 1的项目,但错过了它想要的项目。