volatile变量是否需要同步访问?

Rod*_*eas 9 java synchronization volatile synchronized thread-safety

我在理解Java中的volatile变量时遇到了一些困难.

我有一个参数化类,其中包含一个volatile变量,如下所示:

public class MyClass<T> {

    private volatile T lastValue;

    // ... other code ...

}
Run Code Online (Sandbox Code Playgroud)

我必须实现某些基本操作,以防止lastValue包含get-value-if-not-null.

这些操作是否需要同步?我可以通过以下方法逃脱吗?

public void doSomething() {
    String someString;
    ...
    if (lastValue != null) {
        someString += lastValue.toString();
    }
}
Run Code Online (Sandbox Code Playgroud)

或者我需要将空检查粘贴到同步块中吗?

public void doSomething() {
    String someString;
    ...

    synchronized(this) {
        if (lastValue != null) {
            someString += lastValue.toString();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道对于像get和set这样的原子操作,我应该没有应用同步(例如public T getValue() { return lastValue; }).但我不确定非原子操作.

ass*_*ias 13

volatile 保证可见性(一个线程所做的更改将被其他线程看到),但它不保证多个操作的原子性.

所以,是的,lastValue可能会成为和null之间你的代码可能会抛出一个.if (lastValue != null)someString += lastValue.toString();NullPointerException

您可以添加同步(但是您需要同步对变量的所有写访问),或者对于该简单用例,您可以使用局部变量:

public void doSomething() {
    String someString;
    T lastValueCopy = lastValue;
    if (lastValueCopy != null) {
        someString += lastValueCopy.toString();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @RoddyoftheFrozenPeas这取决于T是什么以及你想要实现的目标.如果你只是想避免NPE,那么我的方法很好.如果T是一个可变的对象,你要根据自己的状态做一次检查,当时的行为(比如你想要做的事,如:!`如果(mutableInteger.value()= 0)结果= 10/mutableInteger.value ();`然后我的方法不够好,因为底层对象可能会从两行之间的非0值变为0,即使您使用共享引用的副本.在这种情况下,您需要深入克隆确实. (2认同)