您現在的位置是:首頁 > 垂釣

java多執行緒——深入瞭解Java記憶體模型與volatile含義

  • 由 java菜鳥到專家 發表于 垂釣
  • 2023-01-09
簡介這裡看出volatile不具備鎖的功能,只是告訴執行緒,一旦變數變化,要去主存中讀取有序性在Java記憶體模型中,允許編譯器和處理器對指令進行重排序,指令重排主要是能夠確保執行速度更快,但是重排序過程不會影響到單執行緒程式的執行,但是在多執

volite是什麼意思

介紹volatile的含義之前,我們先了解下Java的記憶體模型,我們的應用程式在執行的時候,計算在CPU中,資料儲存在記憶體中,但是實際上CPU的計算能力遠遠超過了記憶體的存取速度,為了更好配合CPU的處理速度,在CPU與記憶體之間增加一個快取記憶體,CPU只從Cache中獲取資料。這樣的話,就會存在一個問題,Memory中的資料與Cache中資料存在一致性的問題。

java多執行緒——深入瞭解Java記憶體模型與volatile含義

針對這種資料不一致性的問題,目前的解決方案就是透過快取一致性協議來解決。主要思想噴把有就是當CPU寫資料時,如果該變作機量是共享變數,就是這個變數也存在其他CPU中,那麼就會去通知其他CPU該變數在Cahce中快取無效磷鉛量了,當其他CPU要讀取這個變數的時候,發現變數狀態無效,就會到記憶體中讀取。

Java記憶體模型

Java虛擬機器規範定義一種Java記憶體模型(Java Memory Model,JMM)來遮蔽掉硬體環境帶來的差異,確保java程式能夠正常執行在多個平臺上。

JMM規定:

所有的變數必須存在主記憶體中,每個執行緒都有自身的工作記憶體。

工作記憶體儲存了主記憶體中所有變數的複製,執行緒對這些變數操作都在自身執行緒中完成,不能直接讀寫主記憶體。

執行緒之間無法訪問對方工作記憶體中內容,執行緒之間變數傳遞需要在工作記憶體和主存之間傳遞,都必須經過主記憶體

java多執行緒——深入瞭解Java記憶體模型與volatile含義

JMM規範定義了執行緒工作記憶體與主存之間的儲存關係之後,還要保證在併發程式設計環境下的原子性,可見性,有序性

原子性

在Java語言,對基本資料型別的變數的讀取和賦值操作是原子性操作,即這些操作是不可被中斷的,要麼執行,要麼不執行。說說對這句話的理解,以下圖為例:

java多執行緒——深入瞭解Java記憶體模型與volatile含義

以這四個語句為例,其中具備原子性的語句是哪一個呢?如果說全部都是的話,可能對Java原子性的含義理解不夠,要理解“對基本資料型別的變數的讀取和賦值操作是原子性操作”,也就說讀取與賦值才是原子性的,其他均不是。也就是隻有x=1是原子性。x++,需要讀取x的值然後+1,然後再賦值回x中。y=x,需要讀取x的值,複製到y中,y++與x++一樣,以上語句都是多個賦值與讀取語句組合而成。

所以可以透過synchronized和Lock來實現,對語句和程式碼塊的原子性。由於synchronized和Lock能夠保證任一時刻只有一個執行緒執行該程式碼塊,這樣也就保證了原子性。

可見性

可見性是指當多個執行緒訪問同一個變數時,一旦出現某一個執行緒修改了這個變數的值,那麼其他執行緒能夠立即看得到修改的值。java中使用volatile關鍵字來保證可見性。其主要原理:一個變數被volatile修飾的時候,它的變化立即會更新到主存中,其他執行緒讀取該變數的時候就會去主存中讀取,類似與快取一致性的原理。這裡看出volatile不具備鎖的功能,只是告訴執行緒,一旦變數變化,要去主存中讀取

有序性

在Java記憶體模型中,允許編譯器和處理器對指令進行重排序,指令重排主要是能夠確保執行速度更快,但是重排序過程不會影響到單執行緒程式的執行,但是在多執行緒併發執行過程就會有影響。如下圖:

java多執行緒——深入瞭解Java記憶體模型與volatile含義

在多執行緒環境,加入初始化x=1;那麼在多執行緒環境下,就2個執行緒執行條件下,無法保證x最後是1還是2。因為執行順序無法確定。

java多執行緒——深入瞭解Java記憶體模型與volatile含義

但是可以透過synchronized和Lock來保證有序性,很顯然,synchronized和Lock保證每個時刻是有一個執行緒執行同步程式碼,相當於是讓執行緒順序執行同步程式碼,自然就保證了有序性。

volatile關鍵字的底層原理

一個變數被volatile修飾之後,在多執行緒環境下,一旦有一個執行緒將這個變數做了修改,就會同步到主存中,那麼其他執行緒在獲取的時候,都會從主存中讀取。這個是如何實現的呢?

“觀察加入volatile關鍵字和沒有加入volatile關鍵字時所生成的彙編程式碼發現,加入volatile關鍵字時,會多出一個lock字首指令”這個是《深入理解Java虛擬機器》中的一句話。lock字首指令實際上相當於一個記憶體屏障。它意味著:

1)該指令不會發生重排序。確保指令重排序時不會把其後面的指令排到記憶體屏障之前的位置,也不會把前面的指令排到記憶體屏障的後面。比如下圖:

java多執行緒——深入瞭解Java記憶體模型與volatile含義

比如flag=true這個語句,一定會在語句1,語句2之後(不管語句1和語句2的執行順序),一定會在語句4,語句5之後(不管語句4和語句5順序)

2)它會強制將對快取的修改操作立即寫入主存,這是在彙編指令這一級就規定的了;

3)如果是寫操作,它會導致其他CPU中對應的快取行無效,這樣的話,在CPU讀取的時候,一定要去主存中獲取資料

總結

1。java記憶體模型內容。

2。併發程式設計的原子性,可見性,有序性。對指令重排需要重點理解

3。volatile修飾變數,確保修改之後,其他執行緒能夠知道。

ps:如果您覺得對文章對您有幫助,歡迎點贊,收藏和關注,這將是對我最大肯定

Top