Java同步的getter和setter
private double value; public synchronized void setValue(double value){ this.value=value; } public double getValue(){ return this.value; }
在上面的例子中,是否有任何使getter同步的点?
我认为在这里最好引用Java Concurrency in Practice :
假设只有在写入共享variables时才需要使用同步,这是一个常见的错误; 这是不正确的。
对于每个可被多个线程访问的可变状态variables,对该variables的所有访问必须使用相同的锁执行。 在这种情况下,我们说variables是由该锁保护的。
在没有同步的情况下,编译器,处理器和运行时可以按照操作的执行顺序做一些奇怪的事情。 试图推断在不充分同步的multithreading程序中“必须”发生的内存操作的顺序几乎肯定是不正确的。
通常情况下,你不必对基元进行如此小心,所以如果这是一个int
或boolean
那么可能是这样的:
当一个线程读取一个没有同步的variables时,它可能会看到一个陈旧的值,但是至less它看到的是某个线程实际放置的值,而不是某个随机值。
但是,对于64位操作,这不是真的,例如,如果它们没有被声明为volatile
,则为long
或double
:
Java内存模型要求提取和存储操作是primefaces操作,但对于非易失性的长variables和双variables,允许JVM将64位读取或写入视为两个单独的32位操作。 如果读取和写入发生在不同的线程中,则可以读取非易失性的long,并取回一个值的高32位和另一个的低32位。
因此,即使你不关心陈旧的值,在multithreading程序中使用共享的可变长variables和双variables也是不安全的,除非它们被声明为volatile或被锁保护。
让我通过示例向您展示什么是JIT编译代码的合法途径。 你写:
while (myBean.getValue() > 1.0) { // perform some action Thread.sleep(1); }
JIT编译:
if (myBean.getValue() > 1.0) while (true) { // perform some action Thread.sleep(1); }
在稍微不同的情况下,即使是Java编译器也可能会得到类似的字节码(它只需要消除dynamic分派到不同的getValue
的可能性)。 这是吊装的一个教科书范例。
为什么这是合法的? 编译器有权假定在执行上面的代码时, myBean.getValue()
的结果永远不会改变。 没有synchronized
,允许忽略其他线程的任何操作。
这里的原因是为了防止任何其他线程在线程读取时更新值,从而避免对陈旧值执行任何操作。
这里get方法将会获得“this”上的内部锁,因此任何其他可能尝试使用setter方法设置/更新的线程将不得不等待获取“this”上的锁以进入线程执行获得的setter方法get 。
这就是为什么它build议遵循在可变状态下执行任何操作时使用相同锁的做法。
由于没有复合语句,因此使字段变为volatile将在此处起作用。
需要注意的是,同步方法使用“this”的内部锁。 所以获取并设置两个同步意味着任何进入方法的线程都必须获取locking。
执行非primefaces64位操作时,应特别考虑。 Java Concurrency In Practice的摘录可以帮助您理解这种情况 –
“Java内存模型要求读取和存储操作是primefaces操作,但对于非易失性的长variables和双variables,JVM允许将64位读或写作为两个独立的32位操作。如果读和写操作发生在不同的线程,因此可以读取一个非易失性long值并取回一个值的高32位和另一个值的低32位。因此,即使您不关心陈旧值,也不安全在multithreading程序中使用共享的可变长variables和双variables,除非它们被声明为volatile或由锁保护。
也许对于这个代码看起来很糟糕,但它工作得很好。
private Double value; public void setValue(Double value){ updateValue(value, true); } public Double getValue(){ return updateValue(value, false); } private double updateValue(Double value,boolean set){ synchronized(MyClass.class){ if(set) this.value = value; return value; } }