volatile关键字的作用是什么
今天就跟大家聊聊有關(guān)volatile關(guān)鍵字的作用是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
1、特性
-
1. 可見性:對(duì)一個(gè)volatile 變量的讀,總是能看到(任意線程) 對(duì)這個(gè) volatile 變量最后的寫入。
-
2. 原子性:對(duì)任意單個(gè) volatile 變量的讀/寫 具有原子性,但類似于 volatile++ 這種復(fù)合操作不具有原子性。
2、內(nèi)存語義
內(nèi)存語義:可以簡(jiǎn)單理解為 volatile,sychronize,Atomic,Lock 之類的在 JVM 中的內(nèi)存方面實(shí)現(xiàn)原則。
1、volatile 寫的內(nèi)存語義如下:
當(dāng)寫一個(gè) volatile 變量時(shí),JMM(Java 內(nèi)存模型) 會(huì)把該線程對(duì)應(yīng)的本地內(nèi)存中的共享變量值刷新到主內(nèi)存
2、volatile 讀的內(nèi)存語義如下:
當(dāng)讀到一個(gè) volatile 變量時(shí),JMM會(huì)把改線程對(duì)應(yīng)的本地內(nèi)存職位無效。線程接下來將從只內(nèi)存中讀取共享變量
如果我們將flag變量以volatile關(guān)鍵字修飾,那么實(shí)際上:線程A在寫flag變量后,本地內(nèi)存A中被線程A更新過的兩個(gè)共享變量的值都被刷新到主內(nèi)存中。
在讀flag變量后,本地內(nèi)存B包含的值已經(jīng)被置為無效。此時(shí),線程B必須從主內(nèi)存中讀取共享變量。線程B的讀取操作將導(dǎo)致本地內(nèi)存B與主內(nèi)存中的共享變量的值變成一致。
如果我們把volatile寫和volatile讀兩個(gè)步驟綜合起來看的話,在讀線程B讀一個(gè)volatile變量后,寫線程A在寫這個(gè)volatile變量之前所有可見的共享變量的值都將立即變得對(duì)讀線程B可見。
3、為何volatile不是線程安全的
4、volatile 內(nèi)存語義的實(shí)現(xiàn)
4.1、volatile重排序規(guī)則表
總結(jié)起來就是:
-
當(dāng)?shù)诙€(gè)操作是volatile寫時(shí),不管第一個(gè)操作是什么,都不能重排序。這個(gè)規(guī)則確保volatile寫之前的操作不會(huì)被編譯器重排序到volatile寫之后。
-
當(dāng)?shù)谝粋€(gè)操作是volatile讀時(shí),不管第二個(gè)操作是什么,都不能重排序。這個(gè)規(guī)則確保volatile讀之后的操作不會(huì)被編譯器重排序到volatile讀之前。
-
當(dāng)?shù)谝粋€(gè)操作是volatile寫,第二個(gè)操作是volatile讀時(shí),不能重排序。
4.2、volatile的內(nèi)存屏障
在Java中對(duì)于 volatile 修飾的變量,編譯器在生成字節(jié)碼時(shí),會(huì)在指令序列中插入內(nèi)存屏障來禁止特定類型的處理器重排序問題
什么是內(nèi)存屏障{
Java編譯器在生成指令序列的適當(dāng)位置會(huì)插入內(nèi)存屏障指令來禁止特定類型的處理器重排序,從而讓程序按我們預(yù)想的流程去執(zhí)行。
1、保證特定操作的執(zhí)行順序。
2、影響某些數(shù)據(jù)(或則是某條指令的執(zhí)行結(jié)果)的內(nèi)存可見性。}
volatile寫
-
storestore屏障:對(duì)于這樣的語句store1; storestore; store2,在store2及后續(xù)寫入操作執(zhí)行前,保證store1的寫入操作對(duì)其它處理器可見。(也就是說如果出現(xiàn)storestore屏障,那么store1指令一定會(huì)在store2之前執(zhí)行,CPU不會(huì)store1與store2進(jìn)行重排序)
-
storeload屏障:對(duì)于這樣的語句store1; storeload; load2,在load2及后續(xù)所有讀取操作執(zhí)行前,保證store1的寫入對(duì)所有處理器可見。(也就是說如果出現(xiàn)storeload屏障,那么store1指令一定會(huì)在load2之前執(zhí)行,CPU不會(huì)對(duì)store1與load2進(jìn)行重排序)
volatile讀
在每個(gè)volatile讀操作的后面插入一個(gè)LoadLoad屏障。在每個(gè)volatile讀操作的后面插入一個(gè)loadstore屏障。
-
loadload屏障:對(duì)于這樣的語句load1; loadload; load2,在load2及后續(xù)讀取操作要讀取的數(shù)據(jù)被訪問前,保證load1要讀取的數(shù)據(jù)被讀取完畢。(也就是說,如果出現(xiàn)loadload屏障,那么load1指令一定會(huì)在load2之前執(zhí)行,CPU不會(huì)對(duì)load1與load2進(jìn)行重排序)
-
loadstore屏障:對(duì)于這樣的語句load1; loadstore; store2,在store2及后續(xù)寫入操作被刷出前,保證load1要讀取的數(shù)據(jù)被讀取完畢。(也就是說,如果出現(xiàn)loadstore屏障,那么load1指令一定會(huì)在store2之前執(zhí)行,CPU不會(huì)對(duì)load1與store2進(jìn)行重排序)
5、volatile的實(shí)現(xiàn)原理
通過對(duì) OPEN JDK 中的 unsafe.cpp 源碼的分析,會(huì)發(fā)現(xiàn)被 volatile關(guān)鍵字修飾的變量會(huì)存在一個(gè) “l(fā)ock:” 的前綴。
Lock 前綴,Lock不是一種內(nèi)存屏障,但是它能完成類似于內(nèi)存屏障的功能。Lock 會(huì)對(duì)CPU 總線和高速緩存加鎖,可以理解為 CPU 指令集的一種鎖。
同時(shí)該指令會(huì)將當(dāng)前處理器緩存行的數(shù)據(jù)直接寫到系統(tǒng)內(nèi)存中,且這個(gè)寫回內(nèi)存的操作會(huì)是在其他 CPU 里緩存了該地址的數(shù)據(jù)無效。
再具體的執(zhí)行上,他先對(duì)總線和緩存加鎖,然后執(zhí)行后面的指令,最后釋放鎖會(huì)吧高速緩存中的臟數(shù)據(jù)全部刷新回主內(nèi)存。在 Lock 鎖住總線的時(shí)候,其他 CPU 的讀寫請(qǐng)求會(huì)被阻塞,知道鎖釋放
總結(jié)
以上是生活随笔為你收集整理的volatile关键字的作用是什么的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何使用SAP CRM中间件下载cust
- 下一篇: MySQL技术特点有哪些