[英]Java concurrency: synchronized method and synchronized block
我有两种方法可以从循环缓冲区中添加和删除元素
第一个实现:
synchronized void add(byte b) throws InterruptedException {
if(availableObjects == size) wait();
buffer[(tail+1)%size] = b ;
tail++;
availableObjects++;
notifyAll();
}
synchronized byte remove() throws InterruptedException {
if(head==tail) wait();
Byte element = buffer[head%size];
head ++ ;
availableObjects--;
notifyAll();
return element;
}
和第二个实现:
private final Object addLock= new Object ();
private final Object removeLock=new Object ();
void add (byte b) throws InterruptedException{
synchronized (addLock){
while (availaibleObjects.get () == size) addLock.wait();
buffer [tail]= b;
tail = [tail + 1) % size;
availaibleObjects.incrementAndGet();}
synchronized (removeLock){ // why we added this block ?
removeLock.notifyAll();}
}
byte remove () throws InterruptedException{
byte element;
synchronized (removeLock){
while (availaibleObjects.get () == 0) removeLock.wait() ;
element = buffer[head] ;
head=(head + 1) % size;
availaibleObjects.decrementAndGet();}
synchronized (addLock){ // why we added this block ?
addLock.notifyAll();}
return element;}
我的问题是为什么在方法的第二次实现中我们添加了第二个同步块?
synchronized (removeLock){ // why we added this block ?
removeLock.notifyAll();}
synchronized (addLock){ // why we added this block ?
addLock.notifyAll();}
return element;}
我的问题是为什么在方法的第二次实现中我们添加了第二个同步块?
每当您在 object 上调用wait()
或notify()
时,您必须处于该特定 object 的synchronized
块中。因此,如果您想调用addLock.notifyAll();
您必须在synchronized (addLock)
内。 synchronized
关键字提供锁定以及 memory 同步。
警告:更重要的是,您有一个错误,因为您在addLock
同步块内写入buffer
但在removeLock
内读取。 写入者可以在addLock
内,添加项目,并增加availableObjects
计数器,而读取者已经在addLock
内。 这意味着读取器可能看不到buffer
的更新,并且可能读取一个元素为null
。 如果你正在改变buffer
并稍后从中读取,那么两者都应该保存在同一个 object 上的synchronized
块中——你最好锁定buffer
。 通过此更改,您可以将availableObjects
降级为正常的integer
。
addLock.notifyAll();
如果你这样做正确,你应该能够调用notify()
而不是notifyAll()
因为每个元素添加或从缓冲区中删除将释放最多 1 个等待线程。
if(availableObjects == size) wait();
重要的是要指出您的第二个实现是正确的,可以将这些从if
语句更改为while
语句。 它需要在while
循环中进行测试,否则您将遇到竞争条件和多个发布者和订阅者的错误——在某些架构上也会出现虚假唤醒。 请参阅我关于这些竞争条件的页面。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.