shrunk是什么意思 assign是什么意思( 二 )


store(存儲),作用于工作內存的變量,它把一個從工作內存中一個變量的值傳送到主內存中,以便后續的write使用 。
write(寫入):作用于主內存中的變量,它把store操作從工作內存中得到的變量的值放入主內存的變量中 。
unlock(解鎖):作用于主內存的變量,它把一個處于鎖定狀態的變量釋放出來,釋放后的變量才可以被其他線程鎖定 。
我再補充一下JMM對8種內存交互操作制定的規則吧:
不允許read、load、store、write操作之一單獨出現,也就是read操作后必須load,store操作后必須write 。
不允許線程丟棄他最近的assign操作,即工作內存中的變量數據改變了之后,必須告知主存 。
不允許線程將沒有assign的數據從工作內存同步到主內存 。
一個新的變量必須在主內存中誕生,不允許工作內存直接使用一個未被初始化的變量 。就是對變量實施use、store操作之前,必須經過load和assign操作 。
一個變量同一時間只能有一個線程對其進行lock操作 。多次lock之后,必須執行相同次數unlock才可以解鎖 。
如果對一個變量進行lock操作,會清空所有工作內存中此變量的值 。在執行引擎使用這個變量前,必須重新load或assign操作初始化變量的值 。
如果一個變量沒有被lock,就不能對其進行unlock操作 。也不能unlock一個被其他線程鎖住的變量 。
一個線程對一個變量進行unlock操作之前,必須先把此變量同步回主內存 。
面試官:講一下volatile關鍵字吧
內心:這可是重頭戲呀,可不能出岔子~
很多并發編程都使用了volatile關鍵字,主要的作用包括兩點:
保證線程間變量的可見性 。
禁止CPU進行指令重排序 。
可見性
volatile修飾的變量,當一個線程改變了該變量的值,其他線程是立即可見的 。普通變量則需要重新讀取才能獲得最新值 。
volatile保證可見性的流程大概就是這個一個過程:

shrunk是什么意思 assign是什么意思

文章插圖
volatile一定能保證線程安全嗎
先說結論吧,volatile不能一定能保證線程安全 。
怎么證明呢,我們看下面一段代碼的運行結果就知道了:
/*** @author Ye Hongzhi 公眾號:java技術愛好者**/ public class VolatileTest extends Thread { private static volatile int count = 0; public static void main(String[] args) throws Exception { Vector threads = new Vector(); for (int i = 0; i < 100; i++) { VolatileTest thread = new VolatileTest(); threads.add(thread); thread.start(); } //等待子線程全部完成 for (Thread thread : threads) { thread.join(); } //輸出結果,正確結果應該是1000,實際卻是984 System.out.println(count);//984 } @Override public void run() { for (int i = 0; i < 10; i++) { try { //休眠500毫秒 Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } count++; } } }【shrunk是什么意思 assign是什么意思】為什么volatile不能保證線程安全?
很簡單呀,可見性不能保證操作的原子性,前面說過了count++不是原子性操作,會當做三步,先讀取count的值,然后+1,最后賦值回去count變量 。需要保證線程安全的話,需要使用synchronized關鍵字或者lock鎖,給count++這段代碼上鎖:
private static synchronized void add() { count++; }禁止指令重排序
首先要講一下as-if-serial語義,不管怎么重排序,(單線程)程序的執行結果不能被改變 。
為了使指令更加符合CPU的執行特性,最大限度的發揮機器的性能,提高程序的執行效率,只要程序的最終結果與它順序化情況的結果相等,那么指令的執行順序可以與代碼邏輯順序不一致,這個過程就叫做指令的重排序 。
重排序的種類分為三種,分別是:編譯器重排序,指令級并行的重排序,內存系統重排序 。整個過程如下所示:
shrunk是什么意思 assign是什么意思

文章插圖
指令重排序在單線程是沒有問題的,不會影響執行結果,而且還提高了性能 。但是在多線程的環境下就不能保證一定不會影響執行結果了 。
所以在多線程環境下,就需要禁止指令重排序 。
volatile關鍵字禁止指令重排序有兩層意思:
當程序執行到volatile變量的讀操作或者寫操作時,在其前面的操作的更改肯定全部已經進行,且結果已經對后面的操作可見,在其后面的操作肯定還沒有進行 。
在進行指令優化時,不能將在對volatile變量訪問的語句放在其后面執行,也不能把volatile變量后面的語句放到其前面執行 。
下面舉個例子:

推薦閱讀