volatile的特性:
- volatile可見性:對一個volatile的讀,總可以看到對這個變量最終的寫;
- volatile原子性:volatile對單個讀/寫具有原子性(32位Long、Double),但是復合操作除外,例如:i++;
- jvm底層采用“內存屏障”來實現volatile語義。
volatile的內存語義及實現:
在JMM中,線程之間的通信采用共享內存來實現的。
volatile內存語義是:
- 當寫一個volatile變量時,JMM會把該線程對應的本地內存中的共享變量值立即刷新到主內存中;
- 當讀一個volatile變量時,JMM會把該線程對應的本地內存設置為無效,直接從主內存中讀取共享變量。
volatile的底層實現是通過插入內存屏障,但是對於編譯器來說,發現一個最優布置來最小化插入內存屏障的總數幾乎是不可能的,所以,JMM采用保守策略。如下:
- 在每一個volatile寫操作前面插入一個StoreStore屏障
- 在每一個volatile寫操作后面插入一個StoreLoad屏障
- 在每一個volatile讀操作后面插入一個LoadLoad屏障
- 在每一個volatile讀操作后面插入一個LoadStore屏障
StoreStore屏障可以保證在volatile寫之前,其前面的所有普通寫操作都已經刷新到主內存中;
StoreLoad屏障的作用是避免volatile寫與后面可能有的volatile讀/寫操作重排序
LoadLoad屏障用來禁止處理器把上面的volatile讀與下面的普通讀重排序
LoadStore屏障用來禁止處理器把上面的volatile讀與下面的普通寫重排序
java中volatile關鍵字提供了一個功能,那就是被其修飾的變量在被修改后可以立即同步到主內存,被其修飾的變量在每次使用之前都從主內存刷新。因此,可以使用volatile來保證多線程操作時變量的可見性。
在java中,可以使用synchronized和volatile來保證多線程之間操作的有序性。實現方式有所區別:
- volatile關鍵字會禁止指令重排;
- 2、synchronized關鍵字保證同一時刻只允許一條線程操作。 synchronized是萬能,他可以同時滿足三種特性,這其實也是很多人濫用synchronized的原因。