Java:在双重检查习惯用法中使用局部变量

Java:在双重检查习惯用法中使用局部变量,java,Java,Josh Bloch提到在double check习语中使用局部变量可以提高性能(EJ,第2版,p284),并说示例代码在他的机器上运行速度比没有局部变量的机器快25%。所以问题是,为什么速度更快?局部变量版本访问实例变量3次,正常情况下访问实例变量4次。这是“25%”增长背后的原因还是其他原因 编辑:只有在第一次创建实例时才可以访问3或4次。此后,它是1或2倍 EDIT2:检查此问题的已接受答案以查看示例代码。我认为这是针对Java6的 最基本的事情是访问volatile变量比访问本地变量慢。

Josh Bloch提到在double check习语中使用局部变量可以提高性能(EJ,第2版,p284),并说示例代码在他的机器上运行速度比没有局部变量的机器快25%。所以问题是,为什么速度更快?局部变量版本访问实例变量3次,正常情况下访问实例变量4次。这是“25%”增长背后的原因还是其他原因

编辑:只有在第一次创建实例时才可以访问3或4次。此后,它是1或2倍


EDIT2:检查此问题的已接受答案以查看示例代码。我认为这是针对Java6的

最基本的事情是访问
volatile
变量比访问本地变量慢。当您声明一个局部变量时,基本上是在方法中缓存一个易失性变量的值

在正常(无局部变量)情况下,您正在访问volatile变量:

  • synchronized
    子句之前的第一个
    if
  • synchronized
    子句内的第二个
    if
  • 在第二个
    if
    中,为其赋值
  • return
    语句中
  • 现在,如果引入一个局部变量,则只需访问
    volatile
    变量三次:

  • synchronized
    子句之前的第一个
    if
    指定局部变量时
  • synchronized
    子句内的第二个
    if
    指定局部变量时
  • 在第二个
    if
    中,为其赋值

  • return
    语句中,您不会通过返回局部变量来访问它,从而提高速度。

    在正常情况下(已初始化),只有一次读取volatile变量(相对昂贵)。我猜在这台机器上,这等于他看到的减少量。使用常规方法(即不使用局部变量),有两个读取(一个用于
    if
    ,一个用于
    return

    也许您最好插入一些示例代码,不是所有人都有这本书,还有JVM的哪个版本等。@Zagorulkin Dmitry提供了代码链接。@Nim提供了代码链接,我想版本是6。我们能不能停止称双重检查锁定为一种习惯用法?这是一个模型问题,突出了Java内存模型的某些复杂属性,但它几乎没有实际意义,所有关于它的讨论只会给新手一个错误的印象——即他们应该编写单例,然后用不必要的复杂代码编写它们,这些代码代表了一种荒谬的微优化。@Michael Borgwardt JB在他的EJ书中将这种锁定称为一种习惯用法,所以我猜看到这本书的新手无论如何都会自动称之为习惯用法。这不是我要问的。我问过在双重检查习惯用法中使用局部变量的问题。请参阅上面的EDIT2以获取示例代码。我已经从头重写了整个答案。看看它现在是否回答了你的问题。谢谢。你能评论一下为什么易失性访问速度较慢吗?我所知道的是,读取易失性变量作为内存读取屏障,并清除CPU缓存。这就是它变慢的原因,还是还有其他原因?易失性访问基本上意味着总是引用内存位置,而不是利用处理器缓存。这当然比使用L1/L2缓存慢。