我们真的需要在本地复制 this.myVolatile 来执行 Java 8 中的同步 double if 模式吗?
Do we really need to copy this.myVolatile locally to do the synchronization double if pattern in Java 8?
更改现有代码是否对我们有任何好处:
class MyClass {
volatile Object myVariable;
Object myMethod() {
if (myVariable == null) {
synchronized(this) {
if (myVariable == null) {
myVariable = this.getNewValue();
}
}
}
return myVariable;
}
}
到
class MyClass {
volatile Object myVariable;
Object myMethod() {
Object tmp = this.myVariable;
if (tmp == null) {
synchronized(this) {
tmp = this.myVariable;
if (tmp == null) {
this.myVariable = tmp = this.getNewValue();
}
}
}
return tmp;
}
}
我看不出在使用之前在本地复制 this.myVariable 有什么意义,而且我认为对每个 class 变量使用 "this." 不是一个好习惯。
复制到局部变量更有效也更正确。
更高效:假设在一般情况下,myVariable
是 non-null。在第一个版本中,您 两次 读取 myVariable
,一次检查空值,一次检查 return 值。在第二个版本中,您读取 myVariable
一次,读取 tmp
两次(局部变量访问,这是微不足道的)。使用 volatile 的全部意义在于强大的内存保证,这些保证意味着两次读取是 non-trivial 一次读取的性能损失。
更正确:假设 myVariable
是某种需要定期刷新的 "cache"。 IE。有一个后台线程定期将 myVariable
设置为 null
以便在下次读取时重新加载。在第一个版本中,您 两次 单独读取 myVariable
。第一次读取可能 return 非 null
,然后 "cache refresh" 逻辑运行并将 myVariable
设置为 null
。第二次读取(到return值)然后returns null
!在第二个版本中,tmp
总是 您为 null
测试的值(假设 getNewValue()
从不 returns null
当然)。
请注意,在此代码中使用 "this." 是一种风格选择,与正确性或性能问题无关。
这在很大程度上只是对 https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java 中所述内容的扩展。
更改现有代码是否对我们有任何好处:
class MyClass {
volatile Object myVariable;
Object myMethod() {
if (myVariable == null) {
synchronized(this) {
if (myVariable == null) {
myVariable = this.getNewValue();
}
}
}
return myVariable;
}
}
到
class MyClass {
volatile Object myVariable;
Object myMethod() {
Object tmp = this.myVariable;
if (tmp == null) {
synchronized(this) {
tmp = this.myVariable;
if (tmp == null) {
this.myVariable = tmp = this.getNewValue();
}
}
}
return tmp;
}
}
我看不出在使用之前在本地复制 this.myVariable 有什么意义,而且我认为对每个 class 变量使用 "this." 不是一个好习惯。
复制到局部变量更有效也更正确。
更高效:假设在一般情况下,myVariable
是 non-null。在第一个版本中,您 两次 读取 myVariable
,一次检查空值,一次检查 return 值。在第二个版本中,您读取 myVariable
一次,读取 tmp
两次(局部变量访问,这是微不足道的)。使用 volatile 的全部意义在于强大的内存保证,这些保证意味着两次读取是 non-trivial 一次读取的性能损失。
更正确:假设 myVariable
是某种需要定期刷新的 "cache"。 IE。有一个后台线程定期将 myVariable
设置为 null
以便在下次读取时重新加载。在第一个版本中,您 两次 单独读取 myVariable
。第一次读取可能 return 非 null
,然后 "cache refresh" 逻辑运行并将 myVariable
设置为 null
。第二次读取(到return值)然后returns null
!在第二个版本中,tmp
总是 您为 null
测试的值(假设 getNewValue()
从不 returns null
当然)。
请注意,在此代码中使用 "this." 是一种风格选择,与正确性或性能问题无关。
这在很大程度上只是对 https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java 中所述内容的扩展。