繁体   English   中英

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

[英]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;}

我的问题是为什么在方法的第二次实现中我们添加了第二个同步块?

  1. 从第一个实现我得到两个线程不能同时添加和删除。
  2. 从第二个实现中,两个线程可以同时添加和删除,但我不明白为什么我们添加了这些块:
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.

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