volatile修饰符---内存可见性+禁止重排
~本文小结:
- volatile是一个能保证变量的内存可见性,且禁止重排的修饰符;
- volatile通过设立4个内存屏障避免处理器的重排序;
- volatile可以作为一个锁使用(用于多线程同步);
========================================================================================================================
1、volatile是什么?
- volatile是一个Java修饰符;
- volatile主要用于多线程同步;
2、volatile有啥功能?
volatile能保证变量的内存可见性。翻译成大白话:
被volatile修饰过的变量v,具有以下特点:
- 按照代码顺序,对v的写happens-before对v的读取;
- 只要尝试读取v,则该线程的本地内存立即与主内存同步;
- 只要尝试写入v,则该线程的本地内存的改变,立即同步到主内存;
- v不会和普通变量重排;(在对v操作上面的代码,一定已经被执行过了);
3、volatile如何禁止重排?
通过内存屏障实现。
内存屏障介绍:下述Load代表读操作,Store代表写操作
**LoadLoad屏障:**对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
**StoreStore屏障:**对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
**LoadStore屏障:**对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
**StoreLoad屏障:**对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的(冲刷写缓冲器,清空无效化队列)。在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能
volatile给处理器设立的内存屏障:
- 在每个volatile写操作前插入一个StoreStore屏障;
- 在每个volatile写操作后插入一个StoreLoad屏障;
- 在每个volatile读操作后插入一个LoadLoad屏障+一个LoadStore屏障;
4、volatile有啥用?
- volatile可以保证内存可见性且禁止重排序;
- volatile可以作为一个小小的锁来使用:其保证了对单个volatile变量的读/写具有原子性,且有内存可见性;其在性能上有优势;
- 使用volatile能避免重排带来的问题;(单例模式—“双重锁检查”)
参考:
http://concurrent.redspider.group/article/02/8.html
《深入浅出多线程》