欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

如何解析java多線(xiàn)程volatile內(nèi)存語(yǔ)義

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)如何解析java多線(xiàn)程volatile內(nèi)存語(yǔ)義,文章內(nèi)容豐富且以專(zhuān)業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

專(zhuān)業(yè)網(wǎng)站制作公司,專(zhuān)做排名好的好網(wǎng)站,排在同行前面,為您帶來(lái)客戶(hù)和效益!成都創(chuàng)新互聯(lián)公司為您提供品質(zhì)好成都網(wǎng)站建設(shè),五站合一網(wǎng)站設(shè)計(jì)制作,服務(wù)好的網(wǎng)站設(shè)計(jì)公司,負(fù)責(zé)任的成都網(wǎng)站制作公司!

volatile關(guān)鍵字是java虛擬機(jī)提供的最輕量級(jí)額的同步機(jī)制。由于volatile關(guān)鍵字與java內(nèi)存模型相關(guān),因此,我們?cè)诮榻Bvolatile關(guān)鍵字之前,對(duì)java內(nèi)存模型進(jìn)行更多的補(bǔ)充(之前的博文也曾介紹過(guò))。

1. java內(nèi)存模型(JMM)

JMM是一種規(guī)范,主要用于定義共享變量的訪(fǎng)問(wèn)規(guī)則,目的是解決多個(gè)線(xiàn)程本地內(nèi)存與共享內(nèi)存的數(shù)據(jù)不一致、編譯器處理器的指令重排序造成的各種線(xiàn)程安全問(wèn)題,以保障多線(xiàn)程編程的原子性、可見(jiàn)性和有序性。

JMM規(guī)定了所有的變量都存儲(chǔ)在主內(nèi)存中,每條線(xiàn)程還有自己的工作內(nèi)存,線(xiàn)程中的工作內(nèi)存中存儲(chǔ)了該線(xiàn)程用到的變量的主內(nèi)存的拷貝,各線(xiàn)程對(duì)變量的所有操作都必須在工作內(nèi)存中進(jìn)行,線(xiàn)程之間的變量值的傳遞都必須通過(guò)主內(nèi)存來(lái)進(jìn)行。

JMM定義了8中操作實(shí)現(xiàn)主內(nèi)存與工作內(nèi)存的交互協(xié)議:

1)lock:作用于主內(nèi)存,它把一個(gè)變量標(biāo)識(shí)為一條線(xiàn)程的獨(dú)占狀態(tài)?!   ?)unlock:作用于主內(nèi)存,它把一個(gè)處于鎖定狀態(tài)的變量的釋放出來(lái)?!   ?)read:作用于主內(nèi)存,它把一個(gè)變量的值從主內(nèi)存?zhèn)鬏數(shù)骄€(xiàn)程的工作內(nèi)存中?!   ?)load:作用于工作內(nèi)存,它把從主內(nèi)存中read到的值放入工作內(nèi)存的變量副本中。    5)use:作用于工作內(nèi)存,它把一個(gè)變量的值從主內(nèi)存?zhèn)鬟f給執(zhí)行引擎    6)assign:作用與工作內(nèi)存,它把一個(gè)從執(zhí)行引擎接收到的值賦值給工作內(nèi)存的變量?!   ?)store:作用于工作內(nèi)存,把工作內(nèi)存中一個(gè)變量的值傳送到主內(nèi)存?!   ?)write:作用于主內(nèi)存,它把store操作從工作內(nèi)存中得到的值放入主內(nèi)存中的變量中。

這8中操作以及對(duì)著8中操作的規(guī)則的限制就能確定哪些內(nèi)存訪(fǎng)問(wèn)在并發(fā)條件下是線(xiàn)程安全的,這種方式比較繁瑣,jdk1.5之后提出了提出了happens-before規(guī)則來(lái)判斷線(xiàn)程是否安全。

可以這么理解,happens-before規(guī)則是JMM的核心.Happens-before就是用來(lái)確定兩個(gè)操作的執(zhí)行順序。這兩個(gè)操作可在同一線(xiàn)程中,也可以在兩個(gè)線(xiàn)程中。

happens-before規(guī)定:如果一個(gè)操作happens-before另個(gè)一操作,那么第一個(gè)操作的結(jié)果對(duì)第二個(gè)操作可見(jiàn)(但這并不意味著處理器必須按照happens-before順序執(zhí)行,只要不改變執(zhí)行結(jié)果,可任意優(yōu)化)。happens-before規(guī)則已在前邊博文中介紹,這里不再重復(fù)(http://www.cnblogs.com/gdy1993/p/9117331.html)

JMM內(nèi)存規(guī)則僅僅是一種規(guī)則,規(guī)則的最終落實(shí)是通過(guò)java虛擬機(jī)、編譯器以及處理器一同協(xié)作來(lái)落實(shí)的,而內(nèi)存屏障是java虛擬機(jī)、編譯器、處理器之間溝通的紐帶。

而java原因封裝了這些底層的具體實(shí)現(xiàn)與控制,提供了synchronized、lock和volatile等關(guān)鍵字的來(lái)保障多線(xiàn)程安全問(wèn)題。

2. volatile關(guān)鍵字

(1)volatile對(duì)可見(jiàn)性的保證

在介紹volatile關(guān)鍵字之前,先來(lái)看這樣一段代碼:

//線(xiàn)程1    boolean stop = false;    while(!stop) {      doSomething();    }    //線(xiàn)程2    stop = true;

有兩個(gè)線(xiàn)程:線(xiàn)程1和線(xiàn)程2,線(xiàn)程1在stop==false時(shí),不停的執(zhí)行doSomething()方法;線(xiàn)程2在執(zhí)行到一定情況時(shí),將stop設(shè)置為true,將線(xiàn)程1中斷,很多人采用這種方式中斷線(xiàn)程,但這并不是安全的。因?yàn)閟top作為一個(gè)普通變量,線(xiàn)程2對(duì)其的修改,并不能立刻被線(xiàn)程1所感知,即線(xiàn)程1對(duì)stop的修改僅僅在自己的工作內(nèi)存中,還沒(méi)來(lái)的急寫(xiě)入主內(nèi)存,線(xiàn)程2工作內(nèi)存中的stop并未修改,可能導(dǎo)致線(xiàn)程無(wú)法中斷,雖然這種可能性很小,但一旦發(fā)生,后果嚴(yán)重。

而使用volatile變量修飾就能避免這個(gè)問(wèn)題,這也是volatile第一個(gè)重要含義:

volatile修飾的變量,能夠保證不同線(xiàn)程對(duì)這個(gè)變量操作的可見(jiàn)性,即一個(gè)線(xiàn)程修改了這個(gè)變量的值,這個(gè)新值對(duì)于其他線(xiàn)程是立即可見(jiàn)的。

volatile的對(duì)可見(jiàn)性保證的原理:

對(duì)于volatile修飾的變量,當(dāng)某個(gè)線(xiàn)程對(duì)其進(jìn)行修改時(shí),會(huì)強(qiáng)制將該值刷新到主內(nèi)存,這就使得其他線(xiàn)程對(duì)該變量在各自工作內(nèi)存中的緩存無(wú)效,因而在其他線(xiàn)程對(duì)該變量進(jìn)行操作時(shí),必須從主內(nèi)存中重新加載

(2)volatile對(duì)原子性的保障?

首先來(lái)看這樣一段代碼(深入理解java虛擬機(jī)):

public class VolatileTest {  public static volatile int race = 0;  public static void increase() {    race++;  }  public static final int THREAD_COUNT = 20;  public static void main(String[] args) {    Thread[] threads = new Thread[THREAD_COUNT];    for (Thread t : threads) {      t = new Thread(new Runnable() {        @Override        public void run() {          for(int i = 0; i < 10000; i++) {            increase();          }        }      });      t.start();    }    while(Thread.activeCount() > 1) {      Thread.yield();    }    System.out.println(race);//race < 200000  }}

race是volatile修飾的共享變量,創(chuàng)建20個(gè)線(xiàn)程對(duì)這個(gè)共享變量進(jìn)行自增操作,每個(gè)線(xiàn)程自增的次數(shù)為10000次,如果volatile能夠保證原子性的話(huà),最終race的結(jié)果肯定是200000。但結(jié)果不然,每次程序運(yùn)行race'的值總是小于200000,這也側(cè)面證明了volatile并不能保證共享變量操作的原子性。原理如下:

線(xiàn)程1讀取了race的值,然后cp分配的時(shí)間片結(jié)束,線(xiàn)程2此時(shí)讀取了共享變量的值,并對(duì)race進(jìn)行自增操作,并將操作后的值刷新到主內(nèi)存,此時(shí)線(xiàn)程1已經(jīng)讀取了race的值,因此保留的依然是原來(lái)的值,此時(shí)這個(gè)值已是舊值,對(duì)race進(jìn)行自增操作后刷新到主內(nèi)存,因此主內(nèi)存中的值也是舊值。這也是volatile僅僅能保障讀到的是相對(duì)新值的原因。

(3)volatile對(duì)有序性的保障

首先來(lái)看這樣一段代碼:

//線(xiàn)程1    boolean initialized = false;    context = loadContext();    initialized = true;    //線(xiàn)程2    while(!initialized) {      sleep();    }    doSomething(context);

線(xiàn)程2在initialized變量為true時(shí),使用context變量完成一些操作;線(xiàn)程1負(fù)責(zé)加載context,并在加載完成后將initialized變量設(shè)為true。但是,由于initialized只是一個(gè)普通變量,普通變量?jī)H僅能夠保證在該方法的執(zhí)行過(guò)程中,所有依賴(lài)賦值結(jié)果的地方都能獲得正確的值,而不能保證變量的賦值順序與程序代碼的執(zhí)行順序一致。因此就可能出現(xiàn)這樣一種情況,當(dāng)線(xiàn)程1將initialized變量設(shè)為true時(shí),context依然沒(méi)有加載完成,但線(xiàn)程2由于讀到initialized為true,就可能執(zhí)行了doSomething()方法,可能會(huì)產(chǎn)生非常奇怪的效果。

而volatile的第二個(gè)語(yǔ)義就是禁止重排序: 

寫(xiě)volatile變量的操作與該操作之前的任何讀寫(xiě)操作都不會(huì)被重排序;

讀volatile變量操作與該操作之后的任何讀寫(xiě)操作都不會(huì)重排序。

(4) volatile的底層實(shí)現(xiàn)原理

java語(yǔ)言底層是通過(guò)內(nèi)存屏障來(lái)實(shí)現(xiàn)volatile語(yǔ)義的。

對(duì)于volatile變量的寫(xiě)操作:

①java虛擬機(jī)會(huì)在該操作之前插入一個(gè)釋放屏障(loadstore+storestore),釋放屏障禁止了volatile變量的寫(xiě)操作與該操作之前的任何讀寫(xiě)操作的重排序。

②java虛擬機(jī)會(huì)在該操作之后插入一個(gè)存儲(chǔ)屏障(storeload),存儲(chǔ)屏障使得對(duì)volatile變量的寫(xiě)操作能夠同步到主內(nèi)存。

對(duì)于volatile變量的讀操作:

③java虛擬機(jī)會(huì)在該操作之前插入一個(gè)loadload,使得每次對(duì)volatile變量的讀取都從主內(nèi)存中重新加載(刷新處理器緩存)

④java虛擬機(jī)會(huì)在該操作之后插入一個(gè)獲得屏障(loadstore+loadload),使得volatile后的任何讀寫(xiě)操作與該操作進(jìn)行重排序。

①③保障可見(jiàn)性,②④保障有序性。

(5)volatile關(guān)鍵字與happens-before的關(guān)系

Happens-before規(guī)則中的volatile規(guī)則為:對(duì)于一個(gè)volatile域的寫(xiě)happens-before后續(xù)每一個(gè)針對(duì)該變量的讀操作。

寫(xiě)線(xiàn)程執(zhí)行write(),然后讀線(xiàn)程執(zhí)行read()方法,圖中每個(gè)箭頭都代表一個(gè)happens-before關(guān)系,黑色箭頭是根據(jù)程序順序規(guī)則,藍(lán)色箭頭根據(jù)volatile規(guī)則,紅色箭頭是根據(jù)傳遞性推出的,即操作2happens-before操作3,即對(duì)volatile共享變量的更新操作排在后續(xù)讀取操作之前,對(duì)volatile變量的修改對(duì)后續(xù)volatile變量的讀取可見(jiàn)。

上述就是小編為大家分享的如何解析java多線(xiàn)程volatile內(nèi)存語(yǔ)義了,如果剛好有類(lèi)似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

網(wǎng)頁(yè)名稱(chēng):如何解析java多線(xiàn)程volatile內(nèi)存語(yǔ)義
URL標(biāo)題:http://aaarwkj.com/article10/gopsdo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、品牌網(wǎng)站制作外貿(mào)建站、定制開(kāi)發(fā)關(guān)鍵詞優(yōu)化、Google

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)
人妻少妇精品视频二区| 欧美日韩国产一下老妇| 亚洲小视频免费在线观看| 日韩一区二区三区视频在线看| 日本免费中文字幕在线| 日韩人妻中文字幕乱码一区| 亚洲不卡高清一区二区三区| 日韩黄片大全在线观看| 在线观看永久免费黄色| 黄片无毛欧美在线观看| 亚洲啪啪av一区二区三区| 亚洲一区二区三区精品电影网| 91大片在线观看视频| 亚洲色图熟女激情另类| 天天操天天射夜夜撸| 成人av在线播放亚洲| 91麻豆亚洲国产成人久久| 青青草原三区在线播放| 亚洲美腿丝袜综合在线| 欧美日韩激情在线一区| 丝袜亚洲激情欧美日韩偷拍| 亚洲精品a在线观看av| 日本免费91午夜视频| 91黄色国产在线播放| 麻豆国产原创av色哟哟| 东京热男人的天堂视频| 中文字幕乱码亚洲美女精品| 国产美女自拍视频一区| 日韩亚洲欧美成人一区| 免费av中文字幕电影| 亚洲国产av国产av| 亚洲熟妇av一区二区三区| 男人喜欢看的免费视频| 日韩有码中文字幕av| 欧美私人影院—区二区日本| 日韩一级片精品视频在线| 粗暴蹂躏中文一区二区三区| 亚洲不卡免费在线视频| 日本在线精品在线观看| 国产在线高清精品二区| 天天干夜夜操天天射|