private double value;
public synchronized void setValue(double value) {
this.value = value;
}
public double getValue() {
return this.value;
}
在上面的例子是有在使吸气同步的任何点?
private double value;
public synchronized void setValue(double value) {
this.value = value;
}
public double getValue() {
return this.value;
}
在上面的例子是有在使吸气同步的任何点?
我认为最好举的Java并发实践这里:
这是一个常见的错误的假设,同步需要写入共享变量时要只用; 这是不正确的。
对于可能由多于一个的线程访问每个可变状态变量, 所有访问该变量必须用持有相同的锁定被执行。 在这种情况下,我们说的变量是由锁保护。
在没有同步的,编译器,处理器,和运行时可以做一些非常怪异的东西,其中操作出现执行的顺序。 尝试推理其中内存的动作“必须”在insufflciently同步多线程程序中发生的几乎可以肯定是不正确的顺序。
通常情况下,你不必如此小心元,因此,如果这将是一个int
或boolean
它可能是:
当一个线程读取的变量,而不同步,它可能会看到一个不完整的数值,但至少它认为实际上是由某个线程,而不是一些随机值放在那里的值。
然而,这是不是为64位操作真实的,例如在long
或double
如果他们没有宣布volatile
:
Java内存模型需要提取和存储操作是原子的,但对于非易失性长和双变量,则JVM被允许来治疗64位读或写为两个单独的32位运算。 如果读取和发生在不同的线程写入,因此能够读取的非易失性长,并取回一个值和另一个低32位的高32位。
因此,即使你不关心过时的值,它是不是安全使用共享的可变长双变量在多线程程序,除非它们被声明为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编译器可以prouduce相似的字节码(它只会有消除动态调度的可能性,以不同getValue
)。 这是提升的一个典型例子。
为什么这是合法的吗? 编译器必须假设的结果右侧myBean.getValue()
而上面的代码执行能够永远不会改变。 如果不synchronized
它允许忽略其他线程的任何行动。
这里的原因是为了防止任何其他线程当线程读取更新的价值,从而避免执行上的陈旧价值的任何行动。
这里get方法将收购的“此”,因此任何其他可能尝试使用setter方法来设置/更新线程内部锁将不得不等待获取的“这个”锁进入这已经是由线程执行被收购的setter方法。
这就是为什么它的建议遵循一个可变的状态进行任何操作时,使用同一把锁的做法。
因为没有复合语句制作领域的挥发性将在这里工作。
需要注意的是同步的方法使用内部锁是“本”是很重要的。 因此,获取和设置都被同步意味着进入该方法的任何线程将不得不在此获得锁。
当执行非原子的64位操作应特别注意采取。 从Java并发摘录在实践可以帮助这里了解情况 -
“Java存储模型需要提取和存储操作是原子的,但是对于非挥发性长和双变量,则JVM被允许来治疗64位读或写为两个单独的32位操作。如果读出和发生在写操作不同的线程,因此它可以读取非易失性长,并取回一个价值的高32位,另一低32位。因此,即使你不关心过时的值,它是不是安全使用共享的可变长双变量多线程程序,除非它们被声明为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;
}
}