简体   繁体   English

Java 并发:同步方法和同步块

[英]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?我的问题是为什么在方法的第二次实现中我们添加了第二个同步块?

  1. from the first implementation i get that two threads cannot add and remove at the same time.从第一个实现我得到两个线程不能同时添加和删除。
  2. from the second implementation two threads can add and remove at the same time but i don't understand why we added the blocks:从第二个实现中,两个线程可以同时添加和删除,但我不明白为什么我们添加了这些块:
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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM