我在理解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; }
). 但我不确定非原子操作。
3条答案
按热度按时间x9ybnkn61#
volatile
保证可见性(一个线程所做的更改将被其他线程看到),但不保证多个操作的原子性。所以是的,
lastValue
可能变成null
介于if (lastValue != null)
以及someString += lastValue.toString();
你的代码可能会引发NullPointerException
.您可以添加同步(但需要同步对变量的所有写入访问),或者对于该简单用例,可以使用局部变量:
dpiehjr42#
这在很大程度上取决于t型的特性。在最简单的情况下,t是一个不可变的类型,即无论您读取的t的值是多少,它都不会在以后更改其内部状态。在这种情况下,您不需要同步,只需将引用读入局部变量,并根据需要使用它。
如果t是一个可变类型,那么您需要防止示例在使用它时更改其状态。在这种情况下,您需要特别确保t示例受其保护的同步。在这个上同步通常不能确保,它不会阻止你从任何其他地方改变t的状态。特定t的正确锁必须由规则定义(并且没有语言元素确保您不会违反这些规则)。
在特殊情况下,t是可变的,您将this定义为正确的锁,您需要同步,但不再需要volatile。
也就是说,volatile与synchronized结合使用看起来很可疑。
mi7gmzs63#
并行处理不能保证数据更新对其原点的引用。在这种情况下,必须对作为引用对象操作的进行显式同步。使用synchronized,等待并通知它。
更多详细信息:http://oracle2java.blogspot.com.br/2013/12/java-sincronizar-referencia-entre.html