[英]Java concurrency: synchronized method and synchronized block
i have two methods to add and remove elements from a circular buffer我有两种方法可以从循环缓冲区中添加和删除元素
the first implementation:第一个实现:
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;
}
and the second implementation:和第二个实现:
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;}
my question is why in the second implementation of the methods we added a second synchronized block?我的问题是为什么在方法的第二次实现中我们添加了第二个同步块?
synchronized (removeLock){ // why we added this block ?
removeLock.notifyAll();}
synchronized (addLock){ // why we added this block ?
addLock.notifyAll();}
return element;}
my question is why in the second implementation of the methods we added a second synchronized block?
我的问题是为什么在方法的第二次实现中我们添加了第二个同步块?
Whenever you call wait()
or notify()
on an object, you must be in a synchronized
block for that particular object. So if you want to call addLock.notifyAll();
每当您在 object 上调用
wait()
或notify()
时,您必须处于该特定 object 的synchronized
块中。因此,如果您想调用addLock.notifyAll();
you must be inside a synchronized (addLock)
.您必须在
synchronized (addLock)
内。 The synchronized
keyword provides locking and also memory synchronization. synchronized
关键字提供锁定以及 memory 同步。
WARNING: More importantly, you have a bug because you are writing to buffer
while inside the addLock
synchronized block but reading inside removeLock
.警告:更重要的是,您有一个错误,因为您在
addLock
同步块内写入buffer
但在removeLock
内读取。 A writer could be inside addLock
, add the item, and increment the availableObjects
counter while a reader is already inside of addLock
.写入者可以在
addLock
内,添加项目,并增加availableObjects
计数器,而读取者已经在addLock
内。 This would mean that the reader might not see the updates to buffer
and might read an element as null
.这意味着读取器可能看不到
buffer
的更新,并且可能读取一个元素为null
。 If you are mutating buffer
and then reading from it later, both should be holding in a synchronized
block on the same object – you might as well lock on buffer
.如果你正在改变
buffer
并稍后从中读取,那么两者都应该保存在同一个 object 上的synchronized
块中——你最好锁定buffer
。 With this change you can then downgrade availableObjects
to be a normal integer
.通过此更改,您可以将
availableObjects
降级为正常的integer
。
addLock.notifyAll();
If you do this right, you should be able to call notify()
instead of notifyAll()
since each element added or removed from the buffer will release at most 1 waiting thread.如果你这样做正确,你应该能够调用
notify()
而不是notifyAll()
因为每个元素添加或从缓冲区中删除将释放最多 1 个等待线程。
if(availableObjects == size) wait();
It is important to point out that your 2nd implementation is correct to change these from if
to while
statements.重要的是要指出您的第二个实现是正确的,可以将这些从
if
语句更改为while
语句。 It needs to be tested in a while
loop otherwise you will have race conditions and bugs with multiple publishers and subscribers – also spurious wakeups on some architectures.它需要在
while
循环中进行测试,否则您将遇到竞争条件和多个发布者和订阅者的错误——在某些架构上也会出现虚假唤醒。 See my page on these race conditions .请参阅我关于这些竞争条件的页面。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.