Java并發(fā)編程-volatile可見性詳解
前言
要學習好Java的多線程,就一定得對volatile關鍵字的作用機制了熟于胸。最近博主看了大量關于volatile的相關博客,對其有了一點初步的理解和認識,下面通過自己的話敘述整理一遍。
有什么用?
volatile主要對所修飾的變量提供兩個功能
可見性
防止指令重排序
<br>本篇博客主要對volatile可見性進行探討,以后發(fā)表關于指令重排序的博文。
什么是可見性?

把JAVA內存模型(JMM)展示得很詳細了,簡單概括一下
1.每個Thread有一個屬于自己的工作內存(可以理解為每個廚師有一個屬于自己的鐵鍋)
2.所有Thread共用一個主內存(餐廳所有的廚師共用同一個冰箱)
3.每個Thread操作數(shù)據(jù)之前都會去主內存中獲取數(shù)據(jù)(廚師炒菜之前都要去冰箱里拿食材)
- Thread:廚師
- 工作內存:鐵鍋
- store&load:放熟食,取食材
- 主內存:冰箱
讀者可思考以下情景:<br> 餐廳來了一位顧客點了一份紅燒肉,此時有兩位大廚(假設大廚之間互不通信),由于互不通信,所以兩位大廚都打開冰箱取出食材開始炒菜。 最后炒出了兩份紅燒肉,顧客只要一份。為什么會造成這種結果?
由于大廚之間沒有可見性。
將此情景放在JAVA中即是:<br> 線程A從主內存中取了一個變量到工作內存中,操作完畢后沒有及時放回主內存中,于是線程B去取這個變量已經(jīng)過期了,取的是線程A操作之前的變量。
如何擁有可見性?
先介紹一下Java內存模型中定義的8種工作內存與主內存之間的原子操作
- lock( 鎖定 ):作用于主內存的變量,把一個變量標識為一條線程獨占的狀態(tài)。
- unlock(解鎖):作用于主內存的變量,把一個處于鎖定的變量釋放出來,釋放變量才可以被其他線程鎖定。
- read(讀?。鹤饔糜谥鲀却娴淖兞?,把一個變量的值從主內存?zhèn)鬏數(shù)骄€程的工作內存中,以便隨后的load動作使用。
- load(載入):作用于***工作內存***的變量,它把read操作從主內存中得到的變量值放入工作內存的變量副本中。
- use(使用):作用于***工作內***存種的變量,它把工作內存中一個變量的值傳遞給執(zhí)行引擎,每當虛擬機遇到一個需要使用到變量的值的字節(jié)碼指令時將會執(zhí)行這個操作。
- assign(賦值):作用于***工作內存***中的變量,它把一個從執(zhí)行引擎接收到的值賦給工作內存的變量,每當虛擬機遇到一個給變量賦值的字節(jié)碼指令時執(zhí)行這個操作。
- store(存儲):作用于***工作內存***的變量,它把工作內存中一個變量的值傳送到主內存中,以便隨后的write操作使用
- write(寫入):作用于主內存的變量,它把store操作從工作內存中得到的值放入主內存的變量中。
讀取賦值一個普通變量的情況

發(fā)起read操作到write操作套流程的時間里,線程2隨時都有可能對這個主內存對象發(fā)起第二套操作
有什么危害呢?
假設主內存中有一個
int a=0;
線程1和線程2分別執(zhí)行一次,理想狀態(tài)下最終a的值為2.
a++;
線程1在執(zhí)行了assign操作之后變量a的真實值已經(jīng)從0變成了1,但是這個過程發(fā)生在工作內存中對其他線程不可見,若線程2此時對變量a的操作,讀取到的值仍然為0,因為沒有可見性,線程2的操作也僅僅是重復了線程1的操作,再次讓a從0變成了1。并沒有達到期望的a=2。
讀取賦值一個volatile變量的情況

操作更嚴格:
use之前不能被read&load
assign之后必須緊跟store&write
也就是說 read-load-use 和 assign-store-write成為了兩個不可分割的原子操作
盡管這時候在use和assign之間依然有一段真空期,有可能變量會被其他線程讀取,但是無論在哪一個時間點主內存的變量和任一工作內存的變量的值都是相等的。這個特性就導致了volatile變量不適合參與到依賴當前值的運算,如自增。 那么依靠可見性的特點volatile可以用在哪些地方呢? 《Java虛擬機》提到:
運算結果并不依賴變量的當前值(即結果對產(chǎn)生中間結果不依賴),或者能夠確保只有單一的線程修改變量的值
通常volatile用做保存某個狀態(tài)的boolean值。
以上所述是小編給大家介紹的Java并發(fā)編程-volatile可見性詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關文章
Java中l(wèi)ist根據(jù)id獲取對象的幾種方式
這篇文章主要給大家介紹了關于Java中l(wèi)ist根據(jù)id獲取對象的幾種方式,文中通過實例代碼介紹的非常詳細,對大家學習或者使用java具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07
Java(TM) Platform SE binary 打開jar文件的操作
這篇文章主要介紹了Java(TM) Platform SE binary 打開jar文件的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Java并發(fā)工具之CountDownLatch使用詳解
這篇文章主要介紹了Java并發(fā)工具之CountDownLatch使用詳解,通過使用 CountDownLatch可以使當前線程阻塞,等待其他線程完成給定任務,可以類比旅游團導游要等待所有的游客到齊后才能去下一個景點,需要的朋友可以參考下2023-12-12
springboot快速整合Mybatis組件的方法(推薦)
Spring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發(fā)過程。這篇文章主要介紹了springboot快速整合Mybatis組件的方法,需要的朋友可以參考下2019-11-11

