亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

深入理解Java中的volatile關鍵字(總結篇)

2024-07-14 08:42:40
字體:
來源:轉載
供稿:網友

基本概念

--------------------------------------------------------------------------------

先補充一下概念:Java 內存模型中的可見性、原子性和有序性。

可見性:

  可見性是一種復雜的屬性,因為可見性中的錯誤總是會違背我們的直覺。通常,我們無法確保執行讀操作的線程能適時地看到其他線程寫入的值,有時甚至是根本不可能的事情。為了確保多個線程之間對內存寫入操作的可見性,必須使用同步機制。

  可見性,是指線程之間的可見性,一個線程修改的狀態對另一個線程是可見的。也就是一個線程修改的結果。另一個線程馬上就能看到。比如:用volatile修飾的變量,就會具有可見性。volatile修飾的變量不允許線程內部緩存和重排序,即直接修改內存。所以對其他線程是可見的。但是這里需要注意一個問題,volatile只能讓被他修飾內容具有可見性,但不能保證它具有原子性。比如 volatile int a = 0;之后有一個操作 a++;這個變量a具有可見性,但是a++ 依然是一個非原子操作,也就是這個操作同樣存在線程安全問題。

  在 Java 中 volatile、synchronized 和 final 實現可見性。

原子性:

  原子是世界上的最小單位,具有不可分割性。比如 a=0;(a非long和double類型) 這個操作是不可分割的,那么我們說這個操作時原子操作。再比如:a++; 這個操作實際是a = a + 1;是可分割的,所以他不是一個原子操作。非原子操作都會存在線程安全問題,需要我們使用同步技術(sychronized)來讓它變成一個原子操作。一個操作是原子操作,那么我們稱它具有原子性。java的concurrent包下提供了一些原子類,我們可以通過閱讀API來了解這些原子類的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。

  在 Java 中 synchronized 和在 lock、unlock 中操作保證原子性。

有序性:

  Java 語言提供了 volatile 和 synchronized 兩個關鍵字來保證線程之間操作的有序性,volatile 是因為其本身包含“禁止指令重排序”的語義,synchronized 是由“一個變量在同一個時刻只允許一條線程對其進行 lock 操作”這條規則獲得的,此規則決定了持有同一個對象鎖的兩個同步塊只能串行執行。

正題

在再有人問你Java內存模型是什么,就把這篇文章發給他中我們曾經介紹過,Java語言為了解決并發編程中存在的原子性、可見性和有序性問題,提供了一系列和并發處理相關的關鍵字,比如synchronized、volatile、final、concurren包等。在前一篇文章中,我們也介紹了synchronized的用法及原理。本文,來分析一下另外一個關鍵字——volatile。

本文就圍繞volatile展開,主要介紹volatile的用法、volatile的原理,以及volatile是如何提供可見性和有序性保障的等。

volatile這個關鍵字,不僅僅在Java語言中有,在很多語言中都有的,而且其用法和語義也都是不盡相同的。尤其在C語言、C++以及Java中,都有volatile關鍵字。都可以用來聲明變量或者對象。下面簡單來介紹一下Java語言中的volatile關鍵字。

volatile的用法

volatile通常被比喻成"輕量級的synchronized",也是Java并發編程中比較重要的一個關鍵字。和synchronized不同,volatile是一個變量修飾符,只能用來修飾變量。無法修飾方法及代碼塊等。

volatile的用法比較簡單,只需要在聲明一個可能被多線程同時訪問的變量時,使用volatile修飾就可以了。

public class Singleton {   private volatile static Singleton singleton;   private Singleton (){}   public static Singleton getSingleton() {   if (singleton == null) {     synchronized (Singleton.class) {     if (singleton == null) {       singleton = new Singleton();     }     }   }   return singleton;   } } 

如以上代碼,是一個比較典型的使用雙重鎖校驗的形式實現單例的,其中使用volatile關鍵字修飾可能被多個線程同時訪問到的singleton。

volatile的原理

在再有人問你Java內存模型是什么,就把這篇文章發給他中我們曾經介紹過,為了提高處理器的執行速度,在處理器和內存之間增加了多級緩存來提升。但是由于引入了多級緩存,就存在緩存數據不一致問題。

但是,對于volatile變量,當對volatile變量進行寫操作的時候,JVM會向處理器發送一條lock前綴的指令,將這個緩存中的變量回寫到系統主存中。

但是就算寫回到內存,如果其他處理器緩存的值還是舊的,再執行計算操作就會有問題,所以在多處理器下,為了保證各個處理器的緩存是一致的,就會實現緩存一致性協議

緩存一致性協議:每個處理器通過嗅探在總線上傳播的數據來檢查自己緩存的值是不是過期了,當處理器發現自己緩存行對應的內存地址被修改,就會將當前處理器的緩存行設置成無效狀態,當處理器要對這個數據進行修改操作的時候,會強制重新從系統內存里把數據讀到處理器緩存里。

所以,如果一個變量被volatile所修飾的話,在每次數據變化之后,其值都會被強制刷入主存。而其他處理器的緩存由于遵守了緩存一致性協議,也會把這個變量的值從主存加載到自己的緩存中。這就保證了一個volatile在并發編程中,其值在多個緩存中是可見的。

volatile與可見性

可見性是指當多個線程訪問同一個變量時,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值。

我們在再有人問你Java內存模型是什么,就把這篇文章發給他中分析過:Java內存模型規定了所有的變量都存儲在主內存中,每條線程還有自己的工作內存,線程的工作內存中保存了該線程中是用到的變量的主內存副本拷貝,線程對變量的所有操作都必須在工作內存中進行,而不能直接讀寫主內存。不同的線程之間也無法直接訪問對方工作內存中的變量,線程間變量的傳遞均需要自己的工作內存和主存之間進行數據同步進行。所以,就可能出現線程1改了某個變量的值,但是線程2不可見的情況。

前面的關于volatile的原理中介紹過了,Java中的volatile關鍵字提供了一個功能,那就是被其修飾的變量在被修改后可以立即同步到主內存,被其修飾的變量在每次是用之前都從主內存刷新。因此,可以使用volatile來保證多線程操作時變量的可見性。

volatile與有序性

有序性即程序執行的順序按照代碼的先后順序執行。

我們在再有人問你Java內存模型是什么,就把這篇文章發給他中分析過:除了引入了時間片以外,由于處理器優化和指令重排等,CPU還可能對輸入代碼進行亂序執行,比如load->add->save 有可能被優化成load->save->add 。這就是可能存在有序性問題。

而volatile除了可以保證數據的可見性之外,還有一個強大的功能,那就是他可以禁止指令重排優化等。

普通的變量僅僅會保證在該方法的執行過程中所依賴的賦值結果的地方都能獲得正確的結果,而不能保證變量的賦值操作的順序與程序代碼中的執行順序一致。

volatile可以禁止指令重排,這就保證了代碼的程序會嚴格按照代碼的先后順序執行。這就保證了有序性。被volatile修飾的變量的操作,會嚴格按照代碼順序執行,load->add->save 的執行順序就是:load、add、save。

volatile與原子性

原子性是指一個操作是不可中斷的,要全部執行完成,要不就都不執行。

我們在Java的并發編程中的多線程問題到底是怎么回事兒?中分析過:線程是CPU調度的基本單位。CPU有時間片的概念,會根據不同的調度算法進行線程調度。當一個線程獲得時間片之后開始執行,在時間片耗盡之后,就會失去CPU使用權。所以在多線程場景下,由于時間片在線程間輪換,就會發生原子性問題。

在上一篇文章中,我們介紹synchronized的時候,提到過,為了保證原子性,需要通過字節碼指令monitorenter和monitorexit,但是volatile和這兩個指令之間是沒有任何關系的。

所以,volatile是不能保證原子性的。

在以下兩個場景中可以使用volatile來代替synchronized:

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

2、變量不需要與其他狀態變量共同參與不變約束。

除以上場景外,都需要使用其他方式來保證原子性,如synchronized或者concurrent包。

我們來看一下volatile和原子性的例子:

public class Test {  public volatile int inc = 0;  public void increase() {    inc++;  }  public static void main(String[] args) {    final Test test = new Test();    for(int i=0;i<10;i++){      new Thread(){        public void run() {          for(int j=0;j<1000;j++)            test.increase();        };      }.start();    }    while(Thread.activeCount()>1) //保證前面的線程都執行完      Thread.yield();    System.out.println(test.inc);  }}

以上代碼比較簡單,就是創建10個線程,然后分別執行1000次i++操作。正常情況下,程序的輸出結果應該是10000,但是,多次執行的結果都小于10000。這其實就是volatile無法滿足原子性的原因。

為什么會出現這種情況呢,那就是因為雖然volatile可以保證inc在多個線程之間的可見性。但是無法inc++的原子性。

總結與思考

我們介紹過了volatile關鍵字和synchronized關鍵字?,F在我們知道,synchronized可以保證原子性、有序性和可見性。而volatile卻只能保證有序性和可見性。

那么,我們再來看一下雙重校驗鎖實現的單例,已經使用了synchronized,為什么還需要volatile?

public class Singleton {   private volatile static Singleton singleton;   private Singleton (){}   public static Singleton getSingleton() {   if (singleton == null) {     synchronized (Singleton.class) {     if (singleton == null) {       singleton = new Singleton();     }     }   }   return singleton;   } }

總結

以上所述是小編給大家介紹的Java中的volatile關鍵字,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VeVb武林網網站的支持!


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产亚洲精品久久久| 久久国产精品久久久| 亚洲精品在线视频| 伊人亚洲福利一区二区三区| 国产欧美在线视频| 亚洲在线观看视频网站| 亚洲成人免费在线视频| 久久久最新网址| 久久综合伊人77777蜜臀| 欧美性猛交xxxxx免费看| 91精品国产综合久久久久久久久| 亚洲国产精品成人av| 国色天香2019中文字幕在线观看| 日韩欧美在线看| 国产乱人伦真实精品视频| 久久久噜噜噜久久| 国产国语videosex另类| 亚洲成av人片在线观看香蕉| 亚洲欧美日韩中文视频| 日韩精品视频在线免费观看| 美女性感视频久久久| 色综合91久久精品中文字幕| 这里只有精品在线观看| 亚洲人成网站免费播放| 国产精品劲爆视频| 欧美xxxx做受欧美| 亚洲国产精品va在线| 5566成人精品视频免费| 亚洲日本中文字幕| 91精品免费视频| 久久国产精品久久久久久久久久| 日韩激情视频在线| 欧美激情一区二区三区久久久| 欧美另类在线播放| 午夜精品一区二区三区在线| 欧美激情一区二区三区成人| 日韩中文字幕视频在线| 国内精品美女av在线播放| 91精品国产综合久久香蕉922| 国产精品精品久久久久久| 隔壁老王国产在线精品| 26uuu久久噜噜噜噜| 亚洲第一综合天堂另类专| 欧美极品xxxx| 欧美成人在线免费| 欧洲亚洲女同hd| 国产成人精品视频在线观看| 538国产精品一区二区免费视频| xxav国产精品美女主播| 欧美大全免费观看电视剧大泉洋| 亚洲视频777| 日韩精品视频在线观看免费| 久久成人一区二区| 亚洲国产欧美自拍| 亚洲国产欧美一区二区丝袜黑人| 97色伦亚洲国产| 欧美国产欧美亚洲国产日韩mv天天看完整| 国产中文字幕91| 亚洲成人黄色在线| 日韩精品高清在线观看| 国产在线观看一区二区三区| 欧美麻豆久久久久久中文| 亚洲欧美自拍一区| 久久久成人精品视频| 国产精品嫩草影院久久久| 福利精品视频在线| 日韩经典一区二区三区| 日韩视频在线免费观看| 久久亚洲精品中文字幕冲田杏梨| 91伊人影院在线播放| 国产精品日韩在线观看| 亚洲午夜未满十八勿入免费观看全集| 性欧美激情精品| 成人黄色av网站| 成人动漫网站在线观看| 成人日韩在线电影| 亚洲欧美另类国产| 一区二区在线视频| 亚洲va欧美va国产综合剧情| 中文字幕国产亚洲2019| 色一情一乱一区二区| 日韩美女毛茸茸| 精品中文字幕在线观看| 三级精品视频久久久久| 欧美一级电影在线| 国产欧美精品久久久| 91手机视频在线观看| 成人性生交大片免费观看嘿嘿视频| 国产精品中文字幕在线观看| 激情成人在线视频| 国产精品日韩av| 国产美女扒开尿口久久久| 成人av资源在线播放| 日韩精品免费在线视频| 欧美丝袜第一区| 国产成人精品日本亚洲专区61| 欧美激情videoshd| 91精品国产色综合久久不卡98| 国产99久久精品一区二区| 国产剧情日韩欧美| 亚洲男人的天堂网站| 日韩中文在线中文网在线观看| 日韩av电影在线免费播放| 亚洲天堂第二页| 国产欧美日韩丝袜精品一区| 日韩在线观看免费网站| 91精品免费视频| 中文字幕日韩专区| 国产精品麻豆va在线播放| 国产成人久久精品| 综合136福利视频在线| 日韩精品高清在线观看| 国产精品视频一区二区高潮| 亚洲a区在线视频| 成人动漫网站在线观看| 午夜精品久久久久久久男人的天堂| 美女久久久久久久久久久| 欧美福利视频网站| 中文字幕在线观看亚洲| 亚洲娇小xxxx欧美娇小| 少妇高潮久久77777| 91在线观看免费网站| 国模视频一区二区三区| 亚洲美女喷白浆| 欧美激情欧美激情| 国产精品久久久久久久久久久久久久| 国产香蕉精品视频一区二区三区| 日韩视频免费观看| 欧美成人小视频| 尤物yw午夜国产精品视频| 欧美日韩亚洲一区二区| 97av在线播放| 欧美日韩福利在线观看| 欧美电影在线观看| 亚洲欧美一区二区三区四区| 欧美国产视频日韩| 色悠悠久久久久| 国产精品美女主播在线观看纯欲| 成人av在线网址| 清纯唯美亚洲激情| 欧美精品在线免费| 日韩暖暖在线视频| 欧美激情三级免费| 日韩国产在线播放| 日韩中文在线中文网在线观看| 欧美一级在线亚洲天堂| 日本精品在线视频| 福利一区福利二区微拍刺激| 国产成人精彩在线视频九色| 欧美日韩国产麻豆| 日韩成人高清在线| 日韩精品视频在线观看网址| 538国产精品一区二区免费视频| zzjj国产精品一区二区| 亚洲人在线视频| 精品亚洲夜色av98在线观看| 国产精品免费久久久久久| 成人精品一区二区三区电影免费| 久久99久久99精品中文字幕| 久久久精品视频在线观看| 亚洲精品www久久久| 亚洲精品欧美日韩| 海角国产乱辈乱精品视频| 亚洲视频777|