深刻理解volatile關鍵字

關於volatile關鍵字的話,工做中沒有遇到使用場景,大部分是面試的時候必問的一個題目;
本文主要內容摘自《JAVA高併發編程詳解》java

1. CPU Cache模型

CPU Cache主要是爲了解決CPU與內存之間訪問速度的差別問題,Cache則是在程序運行的過程當中會將運算的所需數據從主內存複製一份到CPU Cache中,這樣CPU在計算的過程當中,能夠直接從CPU Cache中讀取或寫入,當運算結束以後,CPU Cache再將最新數據刷新到主內存當中,CPU直接經過訪問Cache的方式替代直接訪問主存的方式,極大地提升了CPU的吞吐計算能力;面試

2.CPU解決緩存一致性問題

CPU Cache雖然解決了CPU與主存訪問速度差別,但也引來了另一個問題,就是緩存的一致性問題;
好比i++的整個計算過程是這樣的:編程

  1. 讀取主存i的值到CPU Cache中;
  2. 對i進行加一操做;
  3. 將結果寫回到CPU Cache中;
  4. 將數據刷新到主內存中;

在單線程的狀況下,這個計算過程沒有任何問題,可是在多線程狀況下,每一個線程都會將i的值加載到本身的本地內存;
好比如今主內存有i=0,線程A與線程B將變量i加載到了本身的工做內存,此時線程A對i加1操做,寫回主內存,可是在這時候,線程B感知不到線程A的更改,因此線程B對i加一後,刷新到主內存後,主內存的i仍是1;
解決思路:
當CPU在操做Cache中的數據時,若是發現該變量是一個共享變量,也就是說在其餘的CPU Cache中也存在一個副本,那麼進行以下操做: 緩存

  1. 讀取操做:不作任何處理,只是將Cache中的數據讀取到寄存器;
  2. 寫入操做:發出信號通知其餘CPU將該變量在Cache中的狀態設置爲無效,其餘CPU在進行該變量讀取的時候不得不到主內存中再次獲取;

3.java內存模型

Java的內存模型決定了一個線程對共享變量的寫入什麼時候對其餘線程可見,Java內存模型定義了線程和主內存之間的抽象關係:多線程

  • 共享變量存儲於主內存之中,每一個線程均可以訪問;
  • 每一個線程都有私有的工做內存或者稱爲本地內存;
  • 工做內存只存儲該線程對共享變量的副本;
  • 線程不能直接操做主內存,只有先操做了工做內存以後才能寫入主內存;
    深刻理解volatile關鍵字

    假設主內存的共享變量x=0,線程A與線程B分別擁有共享變量x的副本,線程A對x作加1操做後,將x的值刷新到主內存中,當線程B想要使用副本x的時候,就會發現變量已經失效了,必須到主內存中再次獲取而後存入本身的工做內存中;併發

4.JMM如何保證併發三大特性

JMM是指 Java Memory Mode指定了Java虛擬機如何與計算機的主內存進行工做;ide

1) 併發編程的三大特性

(1) 原子性
原子性是指在一次的操做或者屢次操做中,要麼全部的操做所有都獲得了執行而且不會受到任何因素的干擾而中斷,要麼全部的操做都不執行;高併發

(2) 可見性
可見性是指,當一個線程對共享變量進行了修改,那麼另外的線程能夠當即看到修改後的最新值;優化

(3) 有序性
所謂有序性是指程序代碼在執行過程當中的前後順序,好比java編譯器在優化的過程當中會發生指令重排序;線程

2) JMM保證三大特性

(1) JMM與有序性
對基本數據類型的變量讀取賦值操做都是原子性的,對引用類型的變量的讀取與賦值的操做也是原子性的;
可是,若是是i++這類的操做,它在底層其它是進行了兩步操做的,加一和賦值;
(2) JMM與可見性
java提供瞭如下三種方式來保證可見性:

  • 使用validate關鍵字,對於共享變量的寫入首先寫入到工做內存,可是修改結束後會馬上將其刷新到主內存;
  • 經過加鎖的方式實現可見性:不管是synchronized或者Lock,同一時刻只有一個線程得到鎖,而且還會確保在鎖釋放以前,會將對變量的修改刷新到主內存;

(3) JMM與有序性
volatile對一個變量的寫操做要早於對這個變量以後的讀操做;

5.總結

1.能夠保證不一樣線程之間對共享變量操做時的可見性;2.能夠防止指令重排序;3.volatile不能保證原子性;

相關文章
相關標籤/搜索