Java内存模型之volatile的底层实现机制

定义

java 语言规范对volatile 关键字的定义如下

比较重要的一句话是:A file may be declared volatile, in which case the java
Memory Model ensures that all threads see a consistent value for the variable.
理解起来就是,对声明为 volatile 的属性,JMM能确保所有线程对这个属性看到的值是一致的(也就是说 volatile 能提供可见性)。然后我们就可以利用这个可见性大做文章,比如实现一个锁等。

HOW ——> volatile 能提供可见性

   二话不说开始撸代码吧:
public class TestOne  {
    private static volatile int a = 1;

    public static void test() {
            a = 2;     // 5
    }

    public static void main(String [] args) {
        test();
    }
}
 我们利用hsdis插件对上述代码进行反汇编:在控制台输入如下命令
 java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -Xcomp -XX:CompileCommand=compileonly,*TestOne.test TestOne
 参数+PrintAssembly 的意思是打印出汇编代码,对于线上版的Hotspot 想打印出汇编代码需要加上参数+UnlockDiagnosticVMOptions。-Xcomp 参数是让JVM以编译模式执行代码,而不必要等到临界“热点”才触发JIT编译。
-XX:CompileCommand=compileonly,*TestOne.test 意思是只编译test方法,没有这个参数会输出一大推对这次实验没有用的汇编代码。
 结果如下:
    Code:
[Entry Point]
[Verified Entry Point]
[Constants]
  # {method} {0x00007f1718c00258} 'test' '()V' in 'TestOne'
  #           [sp+0x40]  (sp of caller)
  0x00007f1719108de0: mov    %eax,-0x14000(%rsp)
  0x00007f1719108de7: push   %rbp
  0x00007f1719108de8: sub    $0x30,%rsp         ;*iconst_2
                                                ; - TestOne::test@0 (line 5)

  0x00007f1719108dec: movabs $0xf6404248,%rsi   ;   {oop(a 'java/lang/Class' = 'TestOne')}
  0x00007f1719108df6: mov    $0x2,%edi
  0x00007f1719108dfb: mov    %edi,0x68(%rsi)
  0x00007f1719108dfe: lock addl $0x0,(%rsp)     ;*putstatic a
                                                ; - TestOne::test@1 (line 5)

  0x00007f1719108e03: add    $0x30,%rsp
  0x00007f1719108e07: pop    %rbp
  0x00007f1719108e08: test   %eax,0x16dc12f2(%rip)        # 0x00007f172feca100
                                                ;   {poll_return}
看到 lock addl 指令没,它刚好对应 Java源码中的第五行代码。这个 lock 前缀指令,正是volatile 具有可见性的奥秘的所在。
翻一翻 intel 开发手册(卷三第八章)


上面画红圈的表明,处理器对volatile 的实现不是对系统总线进行加锁,而是对缓存加锁。


上面是处理器对缓存加锁的实现方式:
① 对缓存行加锁内容的修改会导致修改后的值马上回写内存
② 该处理器会阻止其他处理器缓存相同的内容(意思就是清空其他处理器中相同的值)

通过 ① ② 处理器的实现机制,java 中的volatile 就可以实现可见性了。



博客内容参考自 《Java 并发编程的艺术》第二章 volatile 的应用

时间: 2024-11-08 18:52:28

Java内存模型之volatile的底层实现机制的相关文章

深入理解Java内存模型(四) volatile

volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解 volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这些单个 读/写操作做了同步.下面我们通过具体的示例来说明,请看下面的示例代码: class VolatileFeaturesExample { volatile long vl = 0L; //使用volatile声明64位的long型变量 public void set(long l) { vl

深入理解Java内存模型(四)——volatile

volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步.下面我们通过具体的示例来说明,请看下面的示例代码: class VolatileFeaturesExample { //使用volatile声明64位的long型变量 volatile long vl = 0L; public void set(long l) { vl = l;

深入理解Java内存模型 - volatile

volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这些单个读/写操作做了同步.下面我们通过具体的示例来说明,请看下面的示例代码: class VolatileFeaturesExample { volatile long vl = 0L; //使用volatile声明64位的long型变量 public void set(long l) { vl =

深入理解Java内存模型系列篇

[本文转载于深入理解Java内存模型,可点击每个章节标题查看原文] 深入理解Java内存模型(一)--基础 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来交换信息.在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递. 在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信.在消息传递的并发模型里,线程之间没有公共状态,线程之间必

Java理论与实践: 修复Java内存模型,第1部分

活跃了将近三年的 JSR 133,近期发布了关于如何修复 Java 内存模型 (Java Memory Model, JMM)的公开建议.原始 JMM 中有几个严重缺陷,这导 致了一些难度高得惊人的概念语义,这些概念原来被认为很简单,如 volatile .final 以及 synchronized.在这一期的 Java 理论与实践 中,Brian Goetz 展示了如何加强 volatile 和 final 的语义,以修复 JMM.这些更改有些已经 集成在 JDK 1.4 中:而另一些将会包含

聊聊我对Java内存模型的理解

所有的编程语言中都有内存模型这个概念,区别于微架构的内存模型,高级语言的内存模型包括了编译器和微架构两部分.我试图了解了Java.C#和Go语言的内存模型,发现内容基本大同小异,只是这些语言在具体实现的时候略有不同. 我们来看看Java内存模型吧,提到Java内存模型大家对这个图一定非常熟悉: 这张图告诉我们在线程运行的时候有一个内存专用的一小块内存,当Java程序会将变量同步到线程所在的内存,这时候会操作工作内存中的变量,而线程中变量的值何时同步回主内存是不可预期的.但同时Java内存模型又告

【转载】JAVA内存模型和线程安全

本文转载自http://shift-alt-ctrl.iteye.com/blog/1845309   一.JAVA内存模型(JMM,JAVA Memory Model):     运行时涉及到两种内存,主内存和工作区内存,其中工作区内存通常为CPU的高速缓存区用来加快内存数据读取操作的(各线程独立).所有的变量内容都存在主内存中,当需要对内存数据进行操作时,数据将会从主存中load到工作区缓存并由CPU计算和赋值操作,然后再由工作区内存write到主存中,读取时如果工作区内存中已经有(load

Akka与Java内存模型的关系

原文链接:http://doc.akka.io/docs/akka/2.3.6/general/jmm.html   译者:clearity 不管你使用的Typesafe系统是Scala版本还是Java版本,都可以使你编写并发程序的过程变得更加容易.这篇文章主要讨论的是Typesafe系统,特别是针对Akka在并发程序中对共享内存的处理部分. Java内存模型 在之前的Java 5 版本中,Java内存模型的定义是很值得商榷的.以至于在共享内存环境下的多线程处理的结果变得多种多样,比如: 线程读

OpenJDK修订Java内存模型

现有的Java内存模型涵盖了很多Java语言的语义保证.在这篇文章中,我们将深入这些语义,并体会对现有Java内存模型更新的动机. 传统的Java内存模型涵盖了很多Java语言的语义保证.在这篇文章中,我们将重点介绍其中的几个语义,以更深入地了解他们.对于本文中描述的语义,我们还将尝试体会对现有Java内存模型更新的动机.本文中与与JMM未来更新相关的讨论,将被称为JMM9. 1. Java内存模型 现有的Java内存模型,如JSR133(以下称为JMM-JSR133)中所定义的,为共享内存指定