volatile的内存语义
volatile写-读的内存语义
volatile写内存定义:当写一个volatile内存变量的时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。也就是说当写一个volatile变量的时候,之前共享变量的操作结果要刷新到主内存,之前的操作不能重排序到该操作之后。
volatile读内存定义:当读一个volatile内存变量的时,JMM会把线程对应的本地内存置为无效。线程接下来从内存中读取共享变量。也就是说当读一个volatile变量时,会从内存中加载到本地内存中,之后对共享变量的操作的值要重新获取,之后的操作不能重排序到该操作之前。
总结:当写一个volatile的时候,此操作之前的共享变量的值会被刷新到主内存中,向其它操作该volatile共享变量的线程发出通知。当读一个volatile共享变量的时候,会重新读取共享变量的值,收到消息,读到其它线程修改的共享变量的值,实现共享变量的可见性。
volatile内存语义的实现
编译重排序
下图为重排序规则表
图表分析
1.当第二个操作是volatile写时,不管第一个操作是什么,都不支持重排序。这个规则确保volatile写之前的操作不会被编译器重排序到volatile之后。
2.当第一个操作是读的时候,不管第二个操作是什么,都不能重排序。这个规则确保volatile读之后的操作不会被编译器重排序到volatile之后。
3.但第一个操作是volatile写,第二个操作是volatile读时,不能重排序。
总结:volatile写操作之前的操作不能重排序到volatile写操作之后(volatile写的内存语义,之前的共享变量操作要刷新到主内存),volatile读操作之后的语句不能重排序到volatile读操作之前(volatile读的内存语义,之后的共享变量操作的值要重新从内存中获取),先volatile写后voilate读可以看做共享变量内存操作的数据依赖不支持重排序,最终实现线程之间操作的可见性。
处理器重排序
1.在每个volatile写操作前插入StoreStore屏障
2.在每个volatile写操作之后插入StoreLoad屏障
3.在每个volatile读操作之后插入一个LoadLoad屏障
4.在每个volatile读操作之后插入一个LoadStore屏障
总结:执行volatile写内存操作时,因为插入StoreStore屏障该操作之前的写内存操作都要先执行,以为之后插入StoreLoad屏障会执行所有的内存操作指令在继续向下执行(volatile写的内存语义);执行volatile读操作时,因为读操作插入LoadLoad屏障和LoadStore屏障,volatile之后的所有内存操作(读和写)不能重排序到该操作之前执行(volatile写操作语义)。
锁的内存语义
锁的释放和获取的内存语义
线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中;线程获取锁时,JMM会把线程对应的本地内存置为无效,从而使得被监视器保护的临界区代码必须从主内存中读取共享变量。
锁内存语义的实现
公平锁通过(AbstractQueuedSynchronizer)AQS,AQS通过修改或读取整型的volatile变量来维护同步状态,非公平锁通过原子操作的compareAndSet方法(CAS)更新state变量实现。
current包实现
- 声明共享变量为volatile。
- 使用CAS的原子条件更新来实现线程间的同步。
- 配合以volatile读/写和CAS锁具备的volatile读写的内存语义来实现线程之间的通行。