volatile的定义
官方:Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。
自我理解:用volatile修饰一个变量,java确保所有线程看到这个变量值一致。当有线程对这个变量进行修改的时候,其他线程在使用的时候会获取这个变量最新更新的值。确保线程的可见性。
volatile有三个特性:原子性(只能保证单步操作),可见性(volatile实现原理来保证),有序性(重排序不影响执行结果)
volatile实现原理
volatile实现体现在有volatile修饰的变量在生成汇编代码的时候会增加一行汇编代码:lock addl $0X0,(%esp)
下面是volatile的两条实现原则
- Lock前缀指令会引起处理器缓存回写到内存。Lock前缀指令导致,声言处理器的LOCK#信号,之前有些处理器中是在总线上声言LOCK#信号,直接能够保证volatile实现。最近的处理器中LOCK#信号锁缓存,它会锁定这个内存区域的缓存并回写到内存,并使用缓存一致性机制来确保修改的原子性,缓存一致性机制会阻止同时修改有两个以上处理器缓存的内存区域数据。
- 处理器的缓存回写到内存会导致其他处理器的缓存无效。每个处理器会嗅探总线上传播的数据来检查自己缓存的值是不是过期,如果被修改,则会把当前处理器的缓存行设置成无效状态。
Volatile内存语义
- 当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。
- 当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。从主内存中读取共享变量。
语义总结:
- 线程A写一个volatile变量,实质上是线程A向接下来将要读这个volatile变量的某个线程发出了(其对共享变量所做修改的)消息。
- 线程B读一个volatile变量,实质上是线程B接收了之前某个线程发出的(在写这个volatile变量之前对共享变量所做修改的)消息。
- 线程A写一个volatile变量,随后线程B读这个volatile变量,这个过程实质上是线程A通过主内存向线程B发送消息。
- 第二个操作(后操作)是 volatile写时,不管先操作的是什么都不能重排序,这个规则确保了volatile写之前的操作不会被编译器重排序到volatile写之后,导致无法更新到主内存。
- 第一个操作(先操作)是 volatile读时,不管后操作的是什么都不能重排序,这个规则确保了volatile读之后的操作不会被编译器重排序到volatile读之前,导致无法从主内存更新最新数据。
- 第一个操作是volatile写,第二个操作是volatile读时,不能重排序。
参考文献:《Java并发编程的艺术》