<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          volatile 關(guān)鍵字分析

          共 858字,需瀏覽 2分鐘

           ·

          2020-10-15 23:22

          點擊上方「藍(lán)字」關(guān)注我們

          一、volatile變量語義一的概念

            當(dāng)一個變量被定義成volatile之后,具備兩個特性:

            特性一:保證此變量對所有線程的可見性。這里的“可見性”是指當(dāng)一條線程修改了這個變量的值,新值對于其他線程來說是可以立即得知的。而普通變量并不能做到這一點,普通變量的值在線程傳遞時均需要通過主內(nèi)存來完成。比如:線程A修改了一個普通變量的值,然后向主內(nèi)存進(jìn)行回寫,另一條線程B在線程A回寫完成了之后再對主內(nèi)存進(jìn)行讀取操作,新變量值才會對線程B可見。

          二、volatile能夠保證線程安全嗎

            基于volatile變量在各個線程中是不存在一致性問題的,從物理存儲的角度看,各個線程的工作內(nèi)存中volatile變量也可以存在不一致的情況,但是由于每次使用前都要進(jìn)行刷新,執(zhí)行引擎看不到不一致的情況,因此也可以人為不存在一致性問題,但是java里面的運算操作符并非是原子操作,這導(dǎo)致了volatile變量的運算在并發(fā)下一樣是不安全的

          案例代碼:

          /**
          ?*?測試Volatile的特性
          ?*/

          public?class?VolatileTest?{
          public?static?volatile??int?race?=?0;

          public?static?void?increase(){
          ???? race++;
          }
          //定義線程的數(shù)量
          private?static?final?int?THREADS_COUNT?=?20;

          public?static?void?main(String[]?args)?{
          ???? Thread[]?threads?=?new?Thread[THREADS_COUNT];
          ???? for(int?i?=?0;i???????? threads[i]?=?new?Thread(new?Runnable()?{
          ???????????? @Override
          ??????????? ?public?void?run()?
          {
          ??????????????? for(int?j?=?0;j<1000;j++){
          ??????????????????? increase();
          ??????????????? }
          ???????????? }
          ???????? });
          ???????? threads[i].start();
          ???????? System.out.println("線程"+i+"開始執(zhí)行");
          ???? }

          ???? while?(Thread.activeCount()>2){
          ???????? System.out.println("Thread.activeCount()?=?"+Thread.activeCount());
          ???????? Thread.yield();//有其他線程等待時,將該線程設(shè)置為就緒狀態(tài)。
          ??? ?}
          ???? System.out.println("race:"+race);
          }
          }

            這段代碼發(fā)起了20個線程,每個線程都對race變量的做了10000次的自增操作,如果是正常的并發(fā)的話,那么race的結(jié)果用該是200000,可是執(zhí)行幾次,發(fā)現(xiàn)結(jié)果并不是200000,而都是一個小于200000的值。這是為什么呢?因為++操作本身就不是原子的,要經(jīng)過讀取計算和寫回,那么,我們通過一張圖模仿一下以上代碼:

            由于變量被volatile修飾,因此這張圖中的3,4操作是連續(xù)不間斷的,5,6,7的操作也是連續(xù)不間斷的,但是經(jīng)過兩個線程的讀取修改寫回操作后,i的值僅僅從1變?yōu)榱?,并不是我們想象的3,

          可能在這里理解上述的圖和描述有點抽象,因為有的朋友可能并不能理解數(shù)據(jù)在主存和緩存中的讀取更改的傳遞規(guī)則,在這里,補充一下變量在內(nèi)存之間的相互操作知識點,大家可以先看以下這塊內(nèi)容,再回過頭進(jìn)行理解上述圖中的操作。

          三:內(nèi)存間的相互操作

          ·lock(鎖定):作用于主內(nèi)存的變量,它把一個變量標(biāo)識為一條線程獨占的狀態(tài)。

          ·unlock(解鎖):作用于主內(nèi)存的變量,它把一個處于鎖定狀態(tài)的變量釋放出來,釋放后的變量才可以被其他線程鎖定。

          ·read(讀取):作用于主內(nèi)存的變量,它把一個變量的值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中,以便隨后的load動作使用。

          ·load(載入):作用于工作內(nèi)存的變量,它把read操作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中。

          ·use(使用):作用于工作內(nèi)存的變量,它把工作內(nèi)存中一個變量的值傳遞給執(zhí)行引擎,每當(dāng)虛擬機遇到一個需要使用變量的值的字節(jié)碼指令時將會執(zhí)行這個操作。

          ·assign(賦值):作用于工作內(nèi)存的變量,它把一個從執(zhí)行引擎接收的值賦給工作內(nèi)存的變量,每當(dāng)虛擬機遇到一個給變量賦值的字節(jié)碼指令時執(zhí)行這個操作。

          ·store(存儲):作用于工作內(nèi)存的變量,它把工作內(nèi)存中一個變量的值傳送到主內(nèi)存中,以便隨后的write操作使用。

          ·write(寫入):作用于主內(nèi)存的變量,它把store操作從工作內(nèi)存中得到的變量的值放入主內(nèi)存的變量中。

          ?   由volatile修飾的變量的特性保證此線程的可見性可知,當(dāng)我們使用volatile修飾了一個變量后,一個線程對此變量的修改對于其他線程來講是立即可知的,也就是說.assign,.store,.write這三個操作是原子的,中間不會間斷,會馬上的同步主存,就像直接操作主存一樣,并通過緩存一致性通知其他的緩存中的副本過期。普通變量可能會在.assign,.store,.write這三個操作中插入其他的操作,導(dǎo)致更改后的數(shù)據(jù)不能立即同步回主存,這種情況在volatile修飾變量時是不存在的。

          四:使用volatile控制并發(fā)的場景

          由于volatile變量只能保證可見性,在不符合以下兩條規(guī)則的運算場景中,我們?nèi)匀灰ㄟ^加鎖(使用synchronized、java.util.concurrent中的鎖或原子類)來保證原子性:

          1、運算結(jié)果并不依賴變量的當(dāng)前值,或者能夠確保只有單一的線程修改變量的值。

          2、變量不需要與其他的狀態(tài)變量共同參與不變約束。

          舉個例子:

          class?VolatileOne{
          volatile?boolean?isShutDown;

          public?void?shutDown(){
          ???? isShutDown?=?true;
          }


          public?void?dowork(){
          ???? while?(!isShutDown){
          ???????? //業(yè)務(wù)代碼
          ???? }
          }
          }

          這類場景就比較適合使用volatile控制并發(fā),當(dāng) shutDown()方法被調(diào)用時,能保證所有
          線程中執(zhí)行的dowork()方法都立即停下來。

          使用volatile變量的第二個特性是禁止指令重排優(yōu)化。

          掃碼二維碼

          獲取更多精彩

          Java樂園

          有用!分享+在看?
          瀏覽 64
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲无 码A片在线观看 | 国产在线资源 | 国产日产精品 | www.色狼人 | 伊人久久成人 |