java “不一致的同步”是什么意思?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4187286/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 05:13:51  来源:igfitidea点击:

What "inconsistent synchronization" means?

javasynchronization

提问by yegor256

This is my Java 1.6 class:

这是我的 Java 1.6 类:

public class Foo {
  private ArrayList<String> names;
  public void scan() {
    if (names == null) {
      synchronized (this) {
        this.names = new ArrayList<String>();
        // fill the array with data
      }
    }
  }
}

Findbugs says:

Findbugs 说:

Inconsistent synchronization of com.XXX.Foo.names; locked 40% of time

What does it mean and what I'm doing wrong? I'm trying to avoid problems when two or more clients call Foo.scan()at the same time.

这是什么意思,我做错了什么?当两个或多个客户同时呼叫Foo.scan()时,我试图避免出现问题。

回答by brain

It's beacuse you are only synchronizing when you set the namesvariable and not when you read it. So between the read and the write another thread could execute and you'd create two ArrayLists and fill them with data, the first one created would get GC'ed.

这是因为您只在设置names变量时同步,而不是在读取时同步。因此,在读取和写入之间,另一个线程可以执行,您将创建两个 ArrayList 并用数据填充它们,创建的第一个将被 GC 处理。

You need to put the synchronized block around the read and the write or add the synchronized modifier to the method.

您需要将同步块放在读取和写入周围,或者向方法添加同步修饰符。

public class Foo {
  private ArrayList<String> names;
    public void scan() {
      synchronized (this)
        if (names == null) {
           this.names = new ArrayList<String>();
           // fill the array with data
         }
       }
     }
  }

回答by Nikita Rybak

The first time you reference namesinside scanis outside of synchronizedblock.
E.g., if scanis called twice from two different threads and namesis null, it may go like this

第一次引用namesinsidescan是在synchronized块外。
例如,如果scan从两个不同的线程调用两次并且names为空,它可能会像这样

  1. if (names == null)from the first thread is processed (to true).
  2. if (names == null)from the second thread is processed (to true).
  3. First thread enters synchronizedblock, assignes namesand leaves synchronizedblock.
  4. Second thread enters synchronizedblock, assignes namesand leaves synchronizedblock.
  1. if (names == null)从第一个线程被处理(到true)。
  2. if (names == null)从第二个线程被处理(到true)。
  3. 第一个线程进入synchronized块,分配names并离开synchronized块。
  4. 第二个线程进入synchronized块,分配names和离开synchronized块。

Now, namesis initialized twice. And this is only one possible scenario where you get unexpected results.

现在,names初始化了两次。这只是您获得意外结果的一种可能情况。