精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Java程序員面試:Volatile全方位解析

開發(fā) 后端
volatile是Java程序員必備的基礎(chǔ),也是面試官非常喜歡問的一個話題,本文跟大家一起開啟vlatile學(xué)習(xí)之旅,如果有不正確的地方,也麻煩大家指出哈,一起相互學(xué)習(xí)~

 前言

volatile是Java程序員必備的基礎(chǔ),也是面試官非常喜歡問的一個話題,本文跟大家一起開啟vlatile學(xué)習(xí)之旅,如果有不正確的地方,也麻煩大家指出哈,一起相互學(xué)習(xí)~

  • 1.volatile的用法
  • 2.vlatile變量的作用
  • 3.現(xiàn)代計算機的內(nèi)存模型(計算機模型,總線,MESI協(xié)議,嗅探技術(shù))
  • 4.Java內(nèi)存模型(JMM)
  • 5.并發(fā)編程的3個特性(原子性、可見性、有序性、happen-before、as-if-serial、指令重排)
  • 6.volatile的底層原理(如何保證可見性,如何保證指令重排,內(nèi)存屏障)
  • 7.volatile的典型場景(狀態(tài)標(biāo)志,DCL單例模式)
  • 8.volatile常見面試題&&答案解析

「github 地址」

❝https://github.com/whx123/JavaHome❞

1.volatile的用法

volatile關(guān)鍵字是Java虛擬機提供的的「最輕量級的同步機制」,它作為一個修飾符出現(xiàn),用來「修飾變量」,但是這里不包括局部變量哦。我們來看個demo吧,代碼如下:

  1. /** 
  2.  *  @Author 撿田螺的小男孩 
  3.  *  @Date 2020/08/02 
  4.  *  @Desc volatile的可見性探索 
  5.  */ 
  6. public class VolatileTest  { 
  7.  
  8.     public static void main(String[] args) throws InterruptedException { 
  9.         Task task = new Task(); 
  10.  
  11.         Thread t1 = new Thread(task, "線程t1"); 
  12.         Thread t2 = new Thread(new Runnable() { 
  13.             @Override 
  14.             public void run() { 
  15.                 try { 
  16.                     Thread.sleep(1000); 
  17.                     System.out.println("開始通知線程停止"); 
  18.                     task.stop = true; //修改stop變量值。 
  19.                 } catch (InterruptedException e) { 
  20.                     e.printStackTrace(); 
  21.                 } 
  22.  
  23.             } 
  24.         }, "線程t2"); 
  25.         t1.start();  //開啟線程t1 
  26.         t2.start();  //開啟線程t2 
  27.         Thread.sleep(1000); 
  28.     } 
  29.  
  30. class Task implements Runnable { 
  31.     boolean stop = false
  32.     int i = 0; 
  33.  
  34.     @Override 
  35.     public void run() { 
  36.         long s = System.currentTimeMillis(); 
  37.         while (!stop) { 
  38.             i++; 
  39.         } 
  40.         System.out.println("線程退出" + (System.currentTimeMillis() - s)); 
  41.     } 

「運行結(jié)果:」

可以發(fā)現(xiàn)線程t2,雖然把stop設(shè)置為true了,但是線程t1對t2的「stop變量視而不可見」,因此,它一直在死循環(huán)running中。如果給變量stop加上volatile修飾,線程t1是可以停下來的,運行結(jié)果如下:

  1. volatile boolean stop = false

 

2. vlatile修飾變量的作用

從以上例子,我們可以發(fā)現(xiàn)變量stop,加了vlatile修飾之后,線程t1對stop就可見了。其實,vlatile的作用就是:「保證變量對所有線程可見性」。當(dāng)然,vlatile還有個作用就是,「禁止指令重排」,但是它「不保證原子性」。

 

所以當(dāng)面試官問你「volatile的作用或者特性」,都可以這么回答:

保證變量對所有線程可見性;

禁止指令重排序

不保證原子性

3. 現(xiàn)代計算機的內(nèi)存模型(計算機模型,MESI協(xié)議,嗅探技術(shù),總線)

為了更好理解volatile,先回顧一下計算機的內(nèi)存模型與JMM(Java內(nèi)存模型)吧~

計算機模型計算機執(zhí)行程序時,指令是由CPU處理器執(zhí)行的,而打交道的數(shù)據(jù)是在主內(nèi)存當(dāng)中的。

由于計算機的存儲設(shè)備與處理器的運算速度有幾個數(shù)量級的差距,總不能每次CPU執(zhí)行完指令,然后等主內(nèi)存慢悠悠存取數(shù)據(jù)吧, 所以現(xiàn)代計算機系統(tǒng)加入一層讀寫速度接近處理器運算速度的高速緩存(Cache),以作為來作為內(nèi)存與處理器之間的緩沖。

在多路處理器系統(tǒng)中,每個處理器都有自己的高速緩存,而它們共享同一主內(nèi)存。「計算機抽象內(nèi)存模型」如下:

 

  • 程序執(zhí)行時,把需要用到的數(shù)據(jù),從主內(nèi)存拷貝一份到高速緩存。
  • CPU處理器計算時,從它的高速緩存中讀取,把計算完的數(shù)據(jù)寫入高速緩存。
  • 當(dāng)程序運算結(jié)束,把高速緩存的數(shù)據(jù)刷新會主內(nèi)存。

隨著科學(xué)技術(shù)的發(fā)展,為了效率,高速緩存又衍生出一級緩存(L1),二級緩存(L2),甚至三級緩存(L3);

 

當(dāng)多個處理器的運算任務(wù)都涉及同一塊主內(nèi)存區(qū)域,可能導(dǎo)致「緩存數(shù)據(jù)不一致」問題。如何解決這個問題呢?有兩種方案

❝1、通過在總線加LOCK#鎖的方式。

2、通過緩存一致性協(xié)議(Cache Coherence Protocol)❞

總線

❝總線(Bus)是計算機各種功能部件之間傳送信息的公共通信干線,它是由導(dǎo)線組成的傳輸線束, 按照計算機所傳輸?shù)男畔⒎N類,計算機的總線可以劃分為數(shù)據(jù)總線、地址總線和控制總線,分別用來傳輸數(shù)據(jù)、數(shù)據(jù)地址和控制信號。❞

CPU和其他功能部件是通過總線通信的,如果在總線加LOCK#鎖,那么在鎖住總線期間,其他CPU是無法訪問內(nèi)存,這樣一來,「效率就比較低了」。

MESI協(xié)議為了解決一致性問題,還可以通過緩存一致性協(xié)議。即各個處理器訪問緩存時都遵循一些協(xié)議,在讀寫時要根據(jù)協(xié)議來進(jìn)行操作,這類協(xié)議有MSI、MESI(IllinoisProtocol)、MOSI、Synapse、Firefly及DragonProtocol等。比較著名的就是Intel的MESI(Modified Exclusive Shared Or Invalid)協(xié)議,它的核心思想是:

❝當(dāng)CPU寫數(shù)據(jù)時,如果發(fā)現(xiàn)操作的變量是共享變量,即在其他CPU中也存在該變量的副本,會發(fā)出信號通知其他CPU將該變量的緩存行置為無效狀態(tài),因此當(dāng)其他CPU需要讀取這個變量時,發(fā)現(xiàn)自己緩存中緩存該變量的緩存行是無效的,那么它就會從內(nèi)存重新讀取。❞

CPU中每個緩存行標(biāo)記的4種狀態(tài)(M、E、S、I),也了解一下吧:

緩存狀態(tài) 描述
M,被修改(Modified) 該緩存行只被該CPU緩存,與主存的值不同,會在它被其他CPU讀取之前寫入內(nèi)存,并設(shè)置為Shared
E,獨享的(Exclusive) 該緩存行只被該CPU緩存,與主存的值相同,被其他CPU讀取時置為Shared,被其他CPU寫時置為Modified
S,共享的(Shared) 該緩存行可能被多個CPU緩存,各個緩存中的數(shù)據(jù)與主存數(shù)據(jù)相同
I,無效的(Invalid) 該緩存行數(shù)據(jù)是無效,需要時需重新從主存載入

MESI協(xié)議是如何實現(xiàn)的?如何保證當(dāng)前處理器的內(nèi)部緩存、主內(nèi)存和其他處理器的緩存數(shù)據(jù)在總線上保持一致的?「多處理器總線嗅探」

嗅探技術(shù)

在多處理器下,為了保證各個處理器的緩存是一致的,就會實現(xiàn)緩存緩存一致性協(xié)議,每個處理器通過嗅探在總線上傳播的數(shù)據(jù)來檢查自己的緩存值是不是過期了,如果處理器發(fā)現(xiàn)自己緩存行對應(yīng)的內(nèi)存地址被修改,就會將當(dāng)前處理器的緩存行設(shè)置無效狀態(tài),當(dāng)處理器對這個數(shù)據(jù)進(jìn)行修改操作的時候,會重新從系統(tǒng)內(nèi)存中把數(shù)據(jù)庫讀到處理器緩存中。❞

4. Java內(nèi)存模型(JMM)

  • Java虛擬機規(guī)范試圖定義一種Java內(nèi)存模型,來「屏蔽掉各種硬件和操作系統(tǒng)的內(nèi)存訪問差異」,以實現(xiàn)讓Java程序在各種平臺上都能達(dá)到一致的內(nèi)存訪問效果。
  • Java內(nèi)存模型「類比」于計算機內(nèi)存模型。
  • 為了更好的執(zhí)行性能,java內(nèi)存模型并沒有限制執(zhí)行引擎使用處理器的特定寄存器或緩存來和主內(nèi)存打交道,也沒有限制編譯器進(jìn)行調(diào)整代碼順序優(yōu)化。所以Java內(nèi)存模型「會存在緩存一致性問題和指令重排序問題的」。
  • Java內(nèi)存模型規(guī)定所有的變量都是存在主內(nèi)存當(dāng)中(類似于計算機模型中的物理內(nèi)存),每個線程都有自己的工作內(nèi)存(類似于計算機模型的高速緩存)。這里的「變量」包括實例變量和靜態(tài)變量,但是「不包括局部變量」,因為局部變量是線程私有的。
  • 線程的工作內(nèi)存保存了被該線程使用的變量的主內(nèi)存副本,「線程對變量的所有操作都必須在工作內(nèi)存中進(jìn)行」,而不能直接操作操作主內(nèi)存。并且每個線程不能訪問其他線程的工作內(nèi)存。

 

舉個例子吧,假設(shè)i的初始值是0,執(zhí)行以下語句:

  1. i = i+1; 

首先,執(zhí)行線程t1從主內(nèi)存中讀取到i=0,到工作內(nèi)存。然后在工作內(nèi)存中,賦值i+1,工作內(nèi)存就得到i=1,最后把結(jié)果寫回主內(nèi)存。因此,如果是單線程的話,該語句執(zhí)行是沒問題的。但是呢,線程t2的本地工作內(nèi)存還沒過期,那么它讀到的數(shù)據(jù)就是臟數(shù)據(jù)了。如圖:

 

Java內(nèi)存模型是圍繞著如何在并發(fā)過程中如何處理「原子性、可見性和有序性」這3個特征來建立的,我們再來一起回顧一下~

5.并發(fā)編程的3個特性(原子性、可見性、有序性)

原子性

原子性,指操作是不可中斷的,要么執(zhí)行完成,要么不執(zhí)行,基本數(shù)據(jù)類型的訪問和讀寫都是具有原子性,當(dāng)然(long和double的非原子性協(xié)定除外)。我們來看幾個小例子:

  1. i =666; // 語句1 
  2. i = j;   // 語句2 
  3. i = i+1;  //語句 3 
  4. i++;   // 語句4 
  • 語句1操作顯然是原子性的,將數(shù)值666賦值給i,即線程執(zhí)行這個語句時,直接將數(shù)值666寫入到工作內(nèi)存中。
  • 語句2操作看起來也是原子性的,但是它實際上涉及兩個操作,先去讀j的值,再把j的值寫入工作內(nèi)存,兩個操作分開都是原子操作,但是合起來就不滿足原子性了。
  • 語句3讀取i的值,加1,再寫回主存,這個就不是原子性操作了。
  • 語句4 等同于語句3,也是非原子性操作。

可見性

  • 可見性就是指當(dāng)一個線程修改了共享變量的值時,其他線程能夠立即得知這個修改。
  • Java內(nèi)存模型是通過在變量修改后將新值同步回主內(nèi)存,在變量讀取前從主內(nèi)存刷新變量值這種依賴主內(nèi)存作為傳遞媒介的方式來實現(xiàn)可見性的,無論是普通變量還是volatile變量都是如此。
  • volatile變量,保證新值能立即同步回主內(nèi)存,以及每次使用前立即從主內(nèi)存刷新,所以我們說volatile保證了多線程操作變量的可見性。
  • synchronized和Lock也能夠保證可見性,線程在釋放鎖之前,會把共享變量值都刷回主存。final也可以實現(xiàn)可見性。

有序性

Java虛擬機這樣描述Java程序的有序性的:如果在本線程內(nèi)觀察,所有的操作都是有序的;如果在一個線程中,觀察另一個線程,所有的操作都是無序的。

后半句意思就是,在Java內(nèi)存模型中,「允許編譯器和處理器對指令進(jìn)行重排序」,會影響到多線程并發(fā)執(zhí)行的正確性;前半句意思就是「as-if-serial」的語義,即不管怎么重排序(編譯器和處理器為了提高并行度),(單線程)程序的執(zhí)行結(jié)果不會被改變。

比如以下程序代碼:

  1. double pi  = 3.14;    //A 
  2. double r   = 1.0;     //B 
  3. double area = pi * r * r; //C 

步驟C依賴于步驟A和B,因為指令重排的存在,程序執(zhí)行順訊可能是A->B->C,也可能是B->A->C,但是C不能在A或者B前面執(zhí)行,這將違反as-if-serial語義。

 

看段代碼吧,假設(shè)程序先執(zhí)行read方法,再執(zhí)行add方法,結(jié)果一定是輸出sum=2嘛?

  1. bool flag = false
  2. int b = 0; 
  3.  
  4. public void read() { 
  5.    b = 1;              //1 
  6.    flag = true;        //2 
  7.  
  8. public void add() { 
  9.    if (flag) {         //3 
  10.        int sum =b+b;   //4 
  11.        System.out.println("bb sum is"+sum);  
  12.    }  

如果是單線程,結(jié)果應(yīng)該沒問題,如果是多線程,線程t1對步驟1和2進(jìn)行了「指令重排序」呢?結(jié)果sum就不是2了,而是0,如下圖所示:

 

這是為啥呢?「指令重排序」了解一下,指令重排是指在程序執(zhí)行過程中,「為了提高性能」, 「編譯器和CPU可能會對指令進(jìn)行重新排序」。CPU重排序包括指令并行重排序和內(nèi)存系統(tǒng)重排序,重排序類型和重排序執(zhí)行過程如下:

 

實際上,可以給flag加上volatile關(guān)鍵字,來保證有序性。當(dāng)然,也可以通過synchronized和Lock來保證有序性。synchronized和Lock保證某一時刻是只有一個線程執(zhí)行同步代碼,相當(dāng)于是讓線程順序執(zhí)行程序代碼了,自然就保證了有序性。

實際上Java內(nèi)存模型的有序性并不是僅靠volatile、synchronized和Lock來保證有序性的。這是因為Java語言中,有一個先行發(fā)生原則(happens-before):

  • 「程序次序規(guī)則」:在一個線程內(nèi),按照控制流順序,書寫在前面的操作先行發(fā)生于書寫在后面的操作。
  • 「管程鎖定規(guī)則」:一個unLock操作先行發(fā)生于后面對同一個鎖額lock操作
  • 「volatile變量規(guī)則」:對一個變量的寫操作先行發(fā)生于后面對這個變量的讀操作
  • 「線程啟動規(guī)則」:Thread對象的start()方法先行發(fā)生于此線程的每個一個動作
  • 「線程終止規(guī)則」:線程中所有的操作都先行發(fā)生于線程的終止檢測,我們可以通過Thread.join()方法結(jié)束、Thread.isAlive()的返回值手段檢測到線程已經(jīng)終止執(zhí)行
  • 「線程中斷規(guī)則」:對線程interrupt()方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測到中斷事件的發(fā)生
  • 「對象終結(jié)規(guī)則」:一個對象的初始化完成先行發(fā)生于他的finalize()方法的開始
  • 「傳遞性」:如果操作A先行發(fā)生于操作B,而操作B又先行發(fā)生于操作C,則可以得出操作A先行發(fā)生于操作C

根據(jù)happens-before的八大規(guī)則,我們回到剛的例子,一起分析一下。給flag加上volatile關(guān)鍵字,look look它是如何保證有序性的,

  1. volatile bool flag = false
  2. int b = 0; 
  3.  
  4. public void read() { 
  5.    b = 1;              //1 
  6.    flag = true;        //2 
  7.  
  8. public void add() { 
  9.    if (flag) {         //3 
  10.        int sum =b+b;   //4 
  11.        System.out.println("bb sum is"+sum);  
  12.    }  
  • 首先呢,flag加上volatile關(guān)鍵字,那就禁止了指令重排,也就是1 happens-before 2了
  • 根據(jù)「volatile變量規(guī)則」,2 happens-before 3
  • 由「程序次序規(guī)則」,得出 3 happens-before 4
  • 最后由「傳遞性」,得出1 happens-before 4,因此妥妥的輸出sum=2啦~

6.volatile底層原理

以上討論學(xué)習(xí),我們知道volatile的語義就是保證變量對所有線程可見性以及禁止指令重排優(yōu)化。那么,它的底層是如何保證可見性和禁止指令重排的呢?

圖解volatile是如何保證可見性的?

在這里,先看幾個圖吧,哈哈~

假設(shè)flag變量的初始值false,現(xiàn)在有兩條線程t1和t2要訪問它,就可以簡化為以下圖:

 

如果線程t1執(zhí)行以下代碼語句,并且flag沒有volatile修飾的話;t1剛修改完flag的值,還沒來得及刷新到主內(nèi)存,t2又跑過來讀取了,很容易就數(shù)據(jù)flag不一致了,如下:

  1. flag=true

 

如果flag變量是由volatile修飾的話,就不一樣了,如果線程t1修改了flag值,volatile能保證修飾的flag變量后,可以「立即同步回主內(nèi)存」。如圖:

 

細(xì)心的朋友會發(fā)現(xiàn),線程t2不還是flag舊的值嗎,這不還有問題嘛?其實volatile還有一個保證,就是「每次使用前立即先從主內(nèi)存刷新最新的值」,線程t1修改完后,線程t2的變量副本會過期了,如圖:

 

顯然,這里還不是底層,實際上volatile保證可見性和禁止指令重排都跟「內(nèi)存屏障」有關(guān),我們編譯volatile相關(guān)代碼看看~

DCL單例模式(volatile)&編譯對比

DCL單例模式(Double Check Lock,雙重檢查鎖)比較常用,它是需要volatile修飾的,所以就拿這段代碼編譯吧

  1. public class Singleton {   
  2.     private volatile static Singleton instance;   
  3.     private Singleton (){}   
  4.     public static Singleton getInstance() {   
  5.     if (instance == null) {   
  6.         synchronized (Singleton.class) {   
  7.         if (instance == null) {   
  8.             instance = new Singleton();   
  9.         }   
  10.         }   
  11.     }   
  12.     return instance;   
  13.     }   
  14. }   

編譯這段代碼后,觀察有volatile關(guān)鍵字和沒有volatile關(guān)鍵字時的instance所生成的匯編代碼發(fā)現(xiàn),有volatile關(guān)鍵字修飾時,會多出一個lock addl $0x0,(%esp),即多出一個lock前綴指令

  1. 0x01a3de0f: mov    $0x3375cdb0,%esi   ;...beb0cd75 33   
  2.                                         ;   {oop('Singleton')}   
  3. 0x01a3de14: mov    %eax,0x150(%esi)   ;...89865001 0000   
  4. 0x01a3de1a: shr    $0x9,%esi          ;...c1ee09   
  5. 0x01a3de1d: movb   $0x0,0x1104800(%esi)  ;...c6860048 100100   
  6. 0x01a3de24: lock addl $0x0,(%esp)     ;...f0830424 00   
  7.                                         ;*putstatic instance   
  8.                                         ; - Singleton::getInstance@24  

lock指令相當(dāng)于一個「內(nèi)存屏障」,它保證以下這幾點:

  • ❝1.重排序時不能把后面的指令重排序到內(nèi)存屏障之前的位置
  • 2.將本處理器的緩存寫入內(nèi)存
  • 3.如果是寫入動作,會導(dǎo)致其他處理器中對應(yīng)的緩存無效。❞

顯然,第2、3點不就是volatile保證可見性的體現(xiàn)嘛,第1點就是禁止指令重排列的體現(xiàn)。

內(nèi)存屏障內(nèi)存屏障四大分類:(Load 代表讀取指令,Store代表寫入指令)

內(nèi)存屏障

內(nèi)存屏障類型 抽象場景 描述
LoadLoad屏障 Load1; LoadLoad; Load2 在Load2要讀取的數(shù)據(jù)被訪問前,保證Load1要讀取的數(shù)據(jù)被讀取完畢。
StoreStore屏障 Store1; StoreStore; Store2 在Store2寫入執(zhí)行前,保證Store1的寫入操作對其它處理器可見
LoadStore屏障 Load1; LoadStore; Store2 在Store2被寫入前,保證Load1要讀取的數(shù)據(jù)被讀取完畢。
StoreLoad屏障 Store1; StoreLoad; Load2 在Load2讀取操作執(zhí)行前,保證Store1的寫入對所有處理器可見。

為了實現(xiàn)volatile的內(nèi)存語義,Java內(nèi)存模型采取以下的保守策略

  • 在每個volatile寫操作的前面插入一個StoreStore屏障。
  • 在每個volatile寫操作的后面插入一個StoreLoad屏障。
  • 在每個volatile讀操作的前面插入一個LoadLoad屏障。
  • 在每個volatile讀操作的后面插入一個LoadStore屏障。

有些小伙伴,可能對這個還是有點疑惑,內(nèi)存屏障這玩意太抽象了。我們照著代碼看下吧:

內(nèi)存屏障保證前面的指令先執(zhí)行,所以這就保證了禁止了指令重排啦,同時內(nèi)存屏障保證緩存寫入內(nèi)存和其他處理器緩存失效,這也就保證了可見性,哈哈~

 

7.volatile的典型場景

通常來說,使用volatile必須具備以下2個條件:

  • 1)對變量的寫操作不依賴于當(dāng)前值
  • 2)該變量沒有包含在具有其他變量的不變式中

實際上,volatile場景一般就是「狀態(tài)標(biāo)志」,以及「DCL單例模式」。

7.1 狀態(tài)標(biāo)志

深入理解Java虛擬機,書中的例子:

  1. Map configOptions; 
  2. char[] configText; 
  3. // 此變量必須定義為 volatile 
  4. volatile boolean initialized = false
  5.  
  6. // 假設(shè)以下代碼在線程 A 中運行 
  7. // 模擬讀取配置信息, 當(dāng)讀取完成后將 initialized 設(shè)置為 true 以告知其他線程配置可用 
  8. configOptions = new HashMap(); 
  9. configText = readConfigFile(fileName); 
  10. processConfigOptions(configText, configOptions); 
  11. initialized = true
  12.        
  13. // 假設(shè)以下代碼在線程 B 中運行 
  14. // 等待 initialized 為 true, 代表線程 A 已經(jīng)把配置信息初始化完成 
  15. while(!initialized) { 
  16.    sleep(); 
  17. // 使用線程 A 中初始化好的配置信息 
  18. doSomethingWithConfig(); 

7.2 DCL單例模式

  1. class Singleton{ 
  2.     private volatile static Singleton instance = null
  3.       
  4.     private Singleton() {    
  5.     } 
  6.       
  7.     public static Singleton getInstance() { 
  8.         if(instance==null) { 
  9.             synchronized (Singleton.class) { 
  10.                 if(instance==null
  11.                     instance = new Singleton(); 
  12.             } 
  13.         } 
  14.         return instance; 
  15.     } 

8. volatile相關(guān)經(jīng)典面試題

  • 談?wù)剉olatile的特性
  • volatile的內(nèi)存語義
  • 說說并發(fā)編程的3大特性
  • 什么是內(nèi)存可見性,什么是指令重排序?
  • volatile是如何解決java并發(fā)中可見性的問題
  • volatile如何防止指令重排
  • volatile可以解決原子性嘛?為什么?
  • volatile底層的實現(xiàn)機制
  • volatile和synchronized的區(qū)別?

8.1 談?wù)剉olatile的特性

 


 

 

8.2 volatile的內(nèi)存語義

當(dāng)寫一個 volatile 變量時,JMM 會把該線程對應(yīng)的本地內(nèi)存中的共享變量值刷新到主內(nèi)存。

當(dāng)讀一個 volatile 變量時,JMM 會把該線程對應(yīng)的本地內(nèi)存置為無效。線程接下來將從主內(nèi)存中讀取共享變量。

8.3 說說并發(fā)編程的3大特性

  • 原子性
  • 可見性
  • 有序性

8.4 什么是內(nèi)存可見性,什么是指令重排序?

可見性就是指當(dāng)一個線程修改了共享變量的值時,其他線程能夠立即得知這個修改。

指令重排是指JVM在編譯Java代碼的時候,或者CPU在執(zhí)行JVM字節(jié)碼的時候,對現(xiàn)有的指令順序進(jìn)行重新排序。

8.5 volatile是如何解決java并發(fā)中可見性的問題

底層是通過內(nèi)存屏障實現(xiàn)的哦,volatile能保證修飾的變量后,可以立即同步回主內(nèi)存,每次使用前立即先從主內(nèi)存刷新最新的值。

8.6 volatile如何防止指令重排

也是內(nèi)存屏障哦,跟面試官講下Java內(nèi)存的保守策略:

  • 在每個volatile寫操作的前面插入一個StoreStore屏障。
  • 在每個volatile寫操作的后面插入一個StoreLoad屏障。
  • 在每個volatile讀操作的前面插入一個LoadLoad屏障。
  • 在每個volatile讀操作的后面插入一個LoadStore屏障。

再講下volatile的語義哦,重排序時不能把內(nèi)存屏障后面的指令重排序到內(nèi)存屏障之前的位置

8.7 volatile可以解決原子性嘛?為什么?不可以,可以直接舉i++那個例子,原子性需要synchronzied或者lock保證

  1. public class Test { 
  2.     public volatile int race = 0; 
  3.       
  4.     public void increase() { 
  5.         race++; 
  6.     } 
  7.       
  8.     public static void main(String[] args) { 
  9.         final Test test = new Test(); 
  10.         for(int i=0;i<10;i++){ 
  11.             new Thread(){ 
  12.                 public void run() { 
  13.                     for(int j=0;j<100;j++) 
  14.                         test.increase(); 
  15.                 }; 
  16.             }.start(); 
  17.         } 
  18.          
  19.         //等待所有累加線程結(jié)束 
  20.         while(Thread.activeCount()>1)   
  21.             Thread.yield(); 
  22.         System.out.println(test.race); 
  23.     } 

8.8 volatile底層的實現(xiàn)機制

可以看本文的第六小節(jié),volatile底層原理哈,主要你要跟面試官講述,volatile如何保證可見性和禁止指令重排,需要講到內(nèi)存屏障~

8.9 volatile和synchronized的區(qū)別?

  • volatile修飾的是變量,synchronized一般修飾代碼塊或者方法
  • volatile保證可見性、禁止指令重排,但是不保證原子性;synchronized可以保證原子性
  • volatile不會造成線程阻塞,synchronized可能會造成線程的阻塞,所以后面才有鎖優(yōu)化那么多故事~
  • 哈哈,你還有補充嘛~

本文轉(zhuǎn)載自微信公眾號「撿田螺的小男孩」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系撿田螺的小男孩公眾號。

 

責(zé)任編輯:武曉燕 來源: 撿田螺的小男孩
相關(guān)推薦

2020-04-20 11:19:00

Java開發(fā)序列化

2009-12-21 15:48:29

WCF應(yīng)用程序

2016-12-14 14:43:11

ButterknifeAndroid

2009-08-24 10:39:12

思科認(rèn)證CCNA思科認(rèn)證CCNA

2011-06-15 14:33:13

2009-09-17 09:01:10

CCNA學(xué)習(xí)指南CCNA

2015-12-24 10:28:37

程序員面試技巧

2016-04-28 11:17:33

互動出版網(wǎng)

2012-05-25 10:15:06

Java程序員面試題

2013-01-10 09:22:58

程序員面試程序員面試經(jīng)歷

2013-02-19 10:12:59

2013-05-14 09:44:41

程序員面試

2015-03-30 15:51:29

程序員程序員面試

2020-01-12 19:10:30

Java程序員數(shù)據(jù)

2010-08-04 14:15:44

nfs服務(wù)

2009-07-02 15:10:17

Java程序員面試

2015-08-19 09:10:37

程序員面試

2024-03-13 13:10:48

JavaInteger緩存

2015-10-10 10:02:44

程序員面試指南

2015-08-19 08:51:38

程序員面試糟糕
點贊
收藏

51CTO技術(shù)棧公眾號

又紧又大又爽精品一区二区| 久久久加勒比| 成人激情视频网站| 欧美野外猛男的大粗鳮| 亚洲91精品在线观看| 亚洲精品国产一区二区三区| 免费在线观看黄色| 国产一区二区三区在线观看精品| 午夜精品123| 激情小说综合网| 特黄视频免费看| 日韩免费高清| 日韩欧美一二区| 91视频 -- 69xx| 国产毛片av在线| 韩国欧美国产1区| 久久久影视精品| 日本性高潮视频| 亚洲一区二区三区四区电影| 狠狠做深爱婷婷久久综合一区| 2019中文字幕在线| 51妺嘿嘿午夜福利| 国产精品一区二区精品| 精品国产福利视频| 日本不卡在线观看| www.com在线观看| 一区二区激情| www日韩中文字幕在线看| 日本人添下边视频免费| 日韩av电影资源网| 国产欧美精品一区aⅴ影院| 热99在线视频| 国产探花在线免费观看| 亚洲丝袜啪啪| 日韩精品资源二区在线| 亚洲熟妇国产熟妇肥婆| 黄色网址在线免费| 久久亚洲综合色| 亚洲综合国产精品| www.色国产| 国产一区激情| 日韩在线视频免费观看高清中文| 蜜臀av免费观看| 国产精品69xx| 国产精品乱码一区二三区小蝌蚪| 国产精品午夜一区二区欲梦| 日韩欧美亚洲视频| 欧美88av| 久久精品国产久精国产一老狼| 亚洲第一狼人区| 亚洲天堂免费电影| 一区二区在线观看不卡| 亚洲一卡二卡| 电影av在线| 91麻豆免费看片| 超碰97在线资源| 国产精品久久久久久免费免熟| 色综合咪咪久久网| 亚洲裸体xxxx| 久久福利小视频| 亚洲影视资源| 欧美性大战久久| 97视频在线免费播放| 久久电影网站| 一区二区视频免费在线观看| 中文字幕在线亚洲精品| 在线看黄色av| 国产精品人妖ts系列视频| 欧美精品在线一区| 男人天堂综合| 久久久久久久免费视频了| 久久人人97超碰人人澡爱香蕉| 国产乱码77777777| 亚欧美中日韩视频| 国内精品久久久久久久| 一区二区在线观看免费视频| 欧美黄色免费| 久久久久亚洲精品成人网小说| 免费在线观看你懂的| 欧美激情极品| 精品一区二区三区电影| 风间由美一二三区av片| 久久91在线| 日韩视频一区在线观看| 国产老头和老头xxxx×| 91久久精品无嫩草影院 | 一区二区三区高清| 亚洲欧洲一二三| 精品51国产黑色丝袜高跟鞋| 亚洲精品中文字幕乱码三区| 日韩久久久久久久久久久久| 麻豆视频在线看| 色婷婷综合激情| 色播五月综合网| 麻豆精品在线| 亚洲国产高清高潮精品美女| 李宗瑞91在线正在播放| 久久麻豆精品| 欧美激情久久久久| 久久夜靖品2区| 视频一区在线播放| 成人在线中文字幕| 欧洲精品久久一区二区| 久久九九全国免费| 伊人久久大香线蕉午夜av| 伊人手机在线| 日本精品免费观看高清观看| 午夜一区二区视频| 美国成人xxx| 91精品啪在线观看国产81旧版| 欧美xfplay| 欧美做受喷浆在线观看| 色综合狠狠操| 2019日本中文字幕| 国产又大又粗又硬| 99在线精品视频| 亚洲国产成人不卡| 欧美韩日亚洲| 日本高清成人免费播放| 色男人天堂av| 精品久久国产| 久久精品视频中文字幕| 偷偷操不一样的久久| 美女免费视频一区二区| 国产日韩一区二区| 欧美jizzhd69巨大| 欧美午夜www高清视频| 日韩爱爱小视频| 久久综合社区| 久久av红桃一区二区小说| 国产精品500部| 国产精品一卡二卡在线观看| 日韩一区二区三区资源| 不卡的av影片| 6080日韩午夜伦伦午夜伦| 亚洲人成人无码网www国产| 欧美午夜电影在线观看| 国产精品一区二区3区| 香蕉av一区二区三区| 亚洲日本一区二区| 国产xxxxx视频| 免费观看成人www动漫视频| 久久综合免费视频| 中文字幕在线观看你懂的| 99re热这里只有精品免费视频| 精品国产免费人成电影在线观...| 黄色一级a毛片| 国产欧美va欧美不卡在线| 国产69精品久久久久999小说| 国产精品xx| 日韩精品一区二区在线观看| 亚洲欧美综合7777色婷婷| 久久久久久穴| 欧美大陆一区二区| 55av亚洲| 精品少妇一区二区三区日产乱码 | 国产精品久久色| 婷婷视频在线观看| 亚洲五月六月丁香激情| 91精品人妻一区二区三区蜜桃2| 亚洲一二av| 久久精品一偷一偷国产| 亚洲精品一区二区二区| 久久精品欧美一区二区三区麻豆| 性欧美18一19内谢| 亚洲免费福利| 亚洲免费伊人电影在线观看av| 亚洲自拍偷拍图| 噜噜噜91成人网| 免费电影一区| 久久sese| 国产一区二区三区在线看| 自拍偷拍校园春色| 欧美国产1区2区| 日韩中文字幕组| 禁断一区二区三区在线| 91干在线观看| 男女污污视频在线观看| 在线精品视频免费观看| 国产又粗又黄又猛| 久久精品国产一区二区| 一区二区三区四区视频在线观看| 大香伊人久久| 日韩av在线网页| 免费黄色网址在线| 亚洲国产精品成人综合| 亚洲一二三av| 亚洲小说欧美另类婷婷| 国产欧美日韩综合一区在线观看| 黄视频在线观看免费| 在线免费观看日本欧美| www成人啪啪18软件| 韩国av一区二区三区在线观看| 久久99导航| 亚洲日本中文| 2019中文字幕全在线观看| 欧美日韩欧美| 亚洲精品国产品国语在线| 亚洲视频在线免费播放| 亚洲国产va精品久久久不卡综合 | 69堂免费精品视频在线播放| 色婷婷久久一区二区| 免费a视频在线观看| 欧美在线短视频| 国产一级做a爱免费视频| 国产亚洲精久久久久久| 一二三区视频在线观看| 奇米四色…亚洲| 色欲色香天天天综合网www| 成人亚洲一区二区| 精品亚洲欧美日韩| 日韩精品一区二区三区中文字幕| 久久躁日日躁aaaaxxxx| 日韩av高清在线| 精品国精品自拍自在线| 亚洲在线观看av| 亚洲大片精品永久免费| 欧美激情精品久久久久久免费 | 欧美一级一区二区三区| 欧美性受极品xxxx喷水| 国产特黄大片aaaa毛片| 亚洲黄色av一区| 懂色av蜜臀av粉嫩av永久| 2021久久国产精品不只是精品| 男人操女人免费| 亚洲国产高清视频| 在线观看免费黄色片| 欧美一区二区麻豆红桃视频| 久久久久久欧美精品色一二三四| 亚洲小少妇裸体bbw| 欧美精品激情blacked18| 免费观看在线午夜影视| 在线看欧美日韩| 蜜桃成人在线视频| 亚洲高清在线观看| 亚洲精品97久久中文字幕| 91精品在线麻豆| 6—12呦国产精品| 欧美人妇做爰xxxⅹ性高电影| 欧美黄色一区二区三区| |精品福利一区二区三区| 成年人在线免费看片| 久久久噜噜噜久久人人看| 国产美女喷水视频| 久久综合色之久久综合| 国产精品三级在线观看无码| 99精品视频一区| 日本黄色免费观看| www.亚洲人| 精品人妻一区二区免费视频| 97se亚洲国产综合自在线观| 在线天堂www在线国语对白| heyzo一本久久综合| 日本道中文字幕| 99久久国产综合精品女不卡| 国产 中文 字幕 日韩 在线| 久久综合色之久久综合| www.黄色在线| 国产精品电影院| www.毛片com| 亚洲国产综合在线| 日本三级网站在线观看| 五月天精品一区二区三区| 日韩经典在线观看| 狠狠色噜噜狠狠狠狠97| 日日夜夜狠狠操| 在线成人免费视频| 亚洲第一成年人网站| 亚洲国产欧美自拍| 国产一区电影| 久久综合免费视频| av中文字幕电影在线看| 欧美自拍视频在线| 国产精品天堂蜜av在线播放| 亚洲已满18点击进入在线看片 | 污污视频在线免费看| 欧美中文字幕一区二区三区亚洲 | 国产福利在线| 日韩在线视频观看| 久久香蕉一区| 日韩免费观看高清| 亚洲日本中文| 久久精品国产精品国产精品污| 深夜激情久久| 久久久久久草| 999国产精品| 91动漫在线看| 视频一区二区中文字幕| 福利视频999| 99视频一区二区| 欧美人与性囗牲恔配| 一区二区在线免费| 亚洲欧美一二三区| 日韩欧美一二三四区| 男人的天堂av高清在线| 久久99精品视频一区97| 欧美成人资源| 国产98在线|日韩| 欧洲视频一区| 欧美午夜性视频| 麻豆91在线观看| 三级黄色片网站| 国产精品不卡一区| 国产黄色片免费看| 日韩精品自拍偷拍| av二区在线| 欧美亚洲一区在线| 亚洲3区在线| 亚洲日本japanese丝袜| 99精品视频网| 国产精品19p| 国产精品久久久久久户外露出| 手机av在线不卡| 亚洲mv大片欧洲mv大片精品| 国产乱叫456在线| 亚洲欧洲xxxx| 成人爽a毛片免费啪啪动漫| 国产精品亚洲激情| 国产精品欧美日韩一区| 欧美极品少妇无套实战| 美女www一区二区| 国产精品探花一区二区在线观看| 99re成人在线| 久久免费黄色网址| 欧美精品xxxxbbbb| 在线免费观看黄色网址| 国产999在线观看| 久久午夜影院| 久久99久久久久久| 国产成人av影院| 日本不卡一二区| 欧美日韩亚洲高清一区二区| 日本福利片高清在线观看| 69av在线播放| 久久精品色综合| 国产男女免费视频| 成人精品视频.| 久久精品久久国产| 日韩精品一区二区三区视频播放 | 忘忧草在线www成人影院| 国产伦精品一区二区三区照片 | 国产美女精品人人做人人爽| 天天躁日日躁aaaa视频| 精品国产成人av| 日韩精品视频无播放器在线看 | 国产伦精品一区二区三区视频黑人| 欧美大片网址| 精品一区二区三区无码视频| 岛国精品在线播放| 国产第一页在线播放| 精品国产百合女同互慰| 9999在线视频| 精品人伦一区二区三区 | 中文字幕精品在线视频| 都市激情亚洲综合| 欧美在线日韩精品| 日韩av电影一区| 国产精品免费人成网站酒店| 日韩一级视频免费观看在线| 久草在线资源站资源站| 国产一区在线免费观看| 三级成人在线视频| 欧美亚洲色综久久精品国产| 欧美嫩在线观看| 日本高清在线观看| 精品久久中出| 日韩中文字幕不卡| 成人三级视频在线观看| 日韩三级av在线播放| free性m.freesex欧美| 欧美国产一区二区在线| 蜜臀av一区二区在线免费观看| 国产高清成人久久| 日本久久一区二区| 国产黄网站在线观看| 国产伦精品一区| 首页国产欧美日韩丝袜| 国产激情无码一区二区三区| 亚洲第一视频在线观看| 免费看av不卡| 欧美xxxx吸乳| 97精品视频在线观看自产线路二| 久久中文字幕在线观看| 日韩高清a**址| 日韩护士脚交太爽了| 青青草精品视频在线| 国产欧美精品国产国产专区 | 亚洲五月婷婷| 国产精品无码午夜福利| 欧美精品一二三区| 女人让男人操自己视频在线观看| 99porn视频在线| 久久精品毛片| 精品国产乱码久久久久久鸭王1| 欧美精品亚洲二区| free性m.freesex欧美| 在线观看免费91| 91婷婷韩国欧美一区二区| 一区二区国产欧美| 97涩涩爰在线观看亚洲|