1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      java中多線程volatile內(nèi)存語義的示例分析

      這篇文章主要為大家展示了“java中多線程volatile內(nèi)存語義的示例分析”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“java中多線程volatile內(nèi)存語義的示例分析”這篇文章吧。

      因為努力和真誠,有更多的客戶和我們聚集在一起,為了共同目標(biāo),成都創(chuàng)新互聯(lián)在工作上密切配合,從創(chuàng)業(yè)型企業(yè)到如今不斷成長,要感謝客戶對我們的高要求,讓我們敢于面對挑戰(zhàn),才有今天的進(jìn)步與發(fā)展。從網(wǎng)站到小程序制作,軟件開發(fā),app軟件定制開發(fā),十載企業(yè)網(wǎng)站建設(shè)服務(wù)經(jīng)驗,為企業(yè)提供網(wǎng)站設(shè)計,網(wǎng)站托管、服務(wù)器托管一條龍服務(wù).為企業(yè)提供全網(wǎng)整合營銷推廣,按需定制網(wǎng)站,原創(chuàng)設(shè)計,十載品質(zhì),值得您的信賴.

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

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

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

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

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

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

      • 2)unlock:作用于主內(nèi)存,它把一個處于鎖定狀態(tài)的變量的釋放出來。

      • 3)read:作用于主內(nèi)存,它把一個變量的值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中。

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

      • 5)use:作用于工作內(nèi)存,它把一個變量的值從主內(nèi)存?zhèn)鬟f給執(zhí)行引擎

      • 6)assign:作用與工作內(nèi)存,它把一個從執(zhí)行引擎接收到的值賦值給工作內(nèi)存的變量。

      • 7)store:作用于工作內(nèi)存,把工作內(nèi)存中一個變量的值傳送到主內(nèi)存。

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

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

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

      happens-before規(guī)定:如果一個操作happens-before另個一操作,那么第一個操作的結(jié)果對第二個操作可見(但這并不意味著處理器必須按照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ī)則的最終落實是通過java虛擬機(jī)、編譯器以及處理器一同協(xié)作來落實的,而內(nèi)存屏障是java虛擬機(jī)、編譯器、處理器之間溝通的紐帶。

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

      2. volatile關(guān)鍵字

      (1)volatile對可見性的保證

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

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

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

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

      volatile修飾的變量,能夠保證不同線程對這個變量操作的可見性,即一個線程修改了這個變量的值,這個新值對于其他線程是立即可見的。

      volatile的對可見性保證的原理:

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

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

      首先來看這樣一段代碼(深入理解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個線程對這個共享變量進(jìn)行自增操作,每個線程自增的次數(shù)為10000次,如果volatile能夠保證原子性的話,最終race的結(jié)果肯定是200000。但結(jié)果不然,每次程序運(yùn)行race'的值總是小于200000,這也側(cè)面證明了volatile并不能保證共享變量操作的原子性。原理如下:

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

      (3)volatile對有序性的保障

      首先來看這樣一段代碼:

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

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

      而volatile的第二個語義就是禁止重排序: 

      寫volatile變量的操作與該操作之前的任何讀寫操作都不會被重排序;

      讀volatile變量操作與該操作之后的任何讀寫操作都不會重排序。

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

      java語言底層是通過內(nèi)存屏障來實現(xiàn)volatile語義的。

      對于volatile變量的寫操作:

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

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

      對于volatile變量的讀操作:

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

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

      ①③保障可見性,②④保障有序性。

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

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

      java中多線程volatile內(nèi)存語義的示例分析

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

      以上是“java中多線程volatile內(nèi)存語義的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


      當(dāng)前文章:java中多線程volatile內(nèi)存語義的示例分析
      瀏覽路徑:http://ef60e0e.cn/article/pogiee.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        舞钢市| 丰顺县| 龙南县| 新化县| 孟州市| 鹤壁市| 乌兰浩特市| 九寨沟县| 长兴县| 两当县| 永仁县| 西宁市| 阆中市| 南投县| 丰原市| 龙井市| 唐河县| 交口县| 焦作市| 伊金霍洛旗| 长宁区| 深水埗区| 棋牌| 广西| 石台县| 神农架林区| 天长市| 孟连| 正宁县| 洛隆县| 安远县| 黄冈市| 满洲里市| 山西省| 东港市| 大同县| 乳山市| 阿拉善左旗| 陆河县| 社旗县| 土默特左旗|