volatile变量需要同步访问吗?

owfi6suc  于 2021-06-30  发布在  Java
关注(0)|答案(3)|浏览(361)

我在理解java中的可变变量时遇到了一点困难。
我有一个参数化类,它包含一个易变变量,如下所示:

public class MyClass<T> {

    private volatile T lastValue;

    // ... other code ...

}

我必须对他们实施一些基本的行动 lastValue 如果不为null,则包含get值。
这些操作需要同步吗?我能用下列方法逃脱惩罚吗?

public void doSomething() {
    String someString;
    ...
    if (lastValue != null) {
        someString += lastValue.toString();
    }
}

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

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

    synchronized(this) {
        if (lastValue != null) {
            someString += lastValue.toString();
        }
    }
}

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

x9ybnkn6

x9ybnkn61#

volatile 保证可见性(一个线程所做的更改将被其他线程看到),但不保证多个操作的原子性。
所以是的, lastValue 可能变成 null 介于 if (lastValue != null) 以及 someString += lastValue.toString(); 你的代码可能会引发 NullPointerException .
您可以添加同步(但需要同步对变量的所有写入访问),或者对于该简单用例,可以使用局部变量:

public void doSomething() {
    String someString;
    T lastValueCopy = lastValue;
    if (lastValueCopy != null) {
        someString += lastValueCopy.toString();
    }
}
dpiehjr4

dpiehjr42#

这在很大程度上取决于t型的特性。在最简单的情况下,t是一个不可变的类型,即无论您读取的t的值是多少,它都不会在以后更改其内部状态。在这种情况下,您不需要同步,只需将引用读入局部变量,并根据需要使用它。
如果t是一个可变类型,那么您需要防止示例在使用它时更改其状态。在这种情况下,您需要特别确保t示例受其保护的同步。在这个上同步通常不能确保,它不会阻止你从任何其他地方改变t的状态。特定t的正确锁必须由规则定义(并且没有语言元素确保您不会违反这些规则)。
在特殊情况下,t是可变的,您将this定义为正确的锁,您需要同步,但不再需要volatile。
也就是说,volatile与synchronized结合使用看起来很可疑。

mi7gmzs6

mi7gmzs63#

并行处理不能保证数据更新对其原点的引用。在这种情况下,必须对作为引用对象操作的进行显式同步。使用synchronized,等待并通知它。
更多详细信息:http://oracle2java.blogspot.com.br/2013/12/java-sincronizar-referencia-entre.html

相关问题