先說說volatile的三個性質吧(過眼也行):
1.可見性;
2.不保證原子性;
3.禁止指令重排序;
再繼續深入volatile之前,再來談談Java內存模型(JMM)
JMM的三個性質:
1.原子性;
2.可見性;
3.有序性;
這三個性質也是并發無法避免的問題。
工作內存圖.png
好了回歸正題,繼續說volatile。
在線程操作共享變量,即上圖主內存中的變量時,會先拷貝一份到本線程的工作內存,然后再對其操作。但這樣也帶來一個問題,就是其中一個線程對這個共享變量修改后,其他線程無法立即感知這個變化,仍使用修改前的值進行操作,那這樣的操作就顯得無意義甚至不安全。
所以使用了volatile來修飾共享變量,它的作用就是保證了對其他線程的可見性,原理就是當線程修改共享變量的值的時候,會將該共享變量刷新回主內存,其他線程立即感知到共享變量已改變,則重寫讀取共享變量的值。進而volatile保證了可見性。
volatile不保證原子性是因為volatile的底層實現并不是OS中的原語操作(即原子性操作),所以要想保證原子性,可以使用JUC包下的原子類。
volatile禁止指令重排的語義:
在執行程序時為了提高性能,編譯器和處理器通常會對指令做重排序:
編譯器重排序。編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執行順序;
處理器重排序。如果不存在數據依賴性,處理器可以改變語句對應機器指令的執行順序;