1. 程式人生 > >10031---Java併發程式設計:volatile關鍵字解析

10031---Java併發程式設計:volatile關鍵字解析

i = 9;

假若一個執行緒執行到這個語句時,我暫且假設為一個32位的變數賦值包括兩個過程:為低16位賦值,為高16位賦值。

那麼就可能發生一種情況:當將低16位數值寫入之後,突然被中斷,而此時又有一個執行緒去讀取i的值,那麼讀取到的就是錯誤的資料。

2.可見性

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

舉個簡單的例子,看下面這段代

//執行緒1執行的程式碼
int i = 0;
i = 10;
 
//執行緒2執行的程式碼
j = i;

假若執行執行緒1的是CPU1,執行執行緒2的是CPU2。由上面的分析可知,當執行緒1執行 i =10這句時,會先把i的初始值載入到CPU1的快取記憶體中,然後賦值為10,那麼在CPU1的快取記憶體當中i的值變為10了,卻沒有立即寫入到主存當中。

此時執行緒2執行 j = i,它會先去主存讀取i的值並載入到CPU2的快取當中,注意此時記憶體當中i的值還是0,那麼就會使得j的值為0,而不是10.

這就是可見性問題,執行緒1對變數i修改了之後,執行緒2沒有立即看到執行緒1修改的值。

3.有序性

有序性:即程式執行的順序按照程式碼的先後順序執行。舉個簡單的例子,看下面這段程式碼:

int i = 0;              
boolean flag = false;
i = 1;                //語句1  
flag = true;          //語句2

上面程式碼定義了一個int型變數,定義了一個boolean型別變數,然後分別對兩個變數進行賦值操作。從程式碼順序上看,語句1是在語句2前面的,

那麼JVM在真正執行這段程式碼的時候會保證語句1一定會在語句2前面執行嗎?不一定,為什麼呢?這裡可能會發生指令重排序(Instruction Reorder)。

下面解釋一下什麼是指令重排序,一般來說,處理器為了提高程式執行效率,可能會對輸入程式碼進行優化,

它不保證程式中各個語句的執行先後順序同程式碼中的順序一致,但是它會保證程式最終執行結果和程式碼順序執行的結果是一致的。

比如上面的程式碼中,語句1和語句2誰先執行對最終的程式結果並沒有影響,那麼就有可能在執行過程中,語句2先執行而語句1後執行。

但是要注意,雖然處理器會對指令進行重排序,但是它會保證程式最終結果會和程式碼順序執行結果相同,那麼它靠什麼保證的呢?再看下面一個例子:

int a = 10;    //語句1
int r = 2;    //語句2
a = a + 3;    //語句3
r = a*a;     //語句4
這段程式碼有4個語句,那麼可能的一個執行順序是:

那麼可不可能是這個執行順序呢: 語句2   語句1    語句4   語句3

不可能,因為處理器在進行重排序時是會考慮指令之間的資料依賴性,如果一個指令Instruction 2必須用到Instruction 1的結果,

那麼處理器會保證Instruction 1會在Instruction 2之前執行。

雖然重排序不會影響單個執行緒內程式執行的結果,但是多執行緒呢?下面看一個例子:

//執行緒1:
context = loadContext();   //語句1
inited = true;             //語句2
 
//執行緒2:
while(!inited ){
  sleep()
}
doSomethingwithconfig(context);

上面程式碼中,由於語句1和語句2沒有資料依賴性,因此可能會被重排序。假如發生了重排序,線上程1執行過程中先執行語句2,

而此是執行緒2會以為初始化工作已經完成,那麼就會跳出while迴圈,去執行doSomethingwithconfig(context)方法,而此時context並沒有被初始化,就會導致程式出錯。

從上面可以看出,指令重排序不會影響單個執行緒的執行,但是會影響到執行緒併發執行的正確性。

也就是說,要想併發程式正確地執行,必須要保證原子性、可見性以及有序性。只要有一個沒有被保證,就有可能會導致程式執行不正確。

三.Java記憶體模型

在前面談到了一些關於記憶體模型以及併發程式設計中可能會出現的一些問題。下面我們來看一下Java記憶體模型,

研究一下Java記憶體模型為我們提供了哪些保證以及在java中提供了哪些方法和機制來讓我們在進行多執行緒程式設計時能夠保證程式執行的正確性。

在Java虛擬機器規範中試圖定義一種Java記憶體模型(Java Memory Model,JMM)來遮蔽各個硬體平臺和作業系統的記憶體訪問差異,

以實現讓Java程式在各種平臺下都能達到一致的記憶體訪問效果。那麼Java記憶體模型規定了哪些東西呢,

它定義了程式中變數的訪問規則,往大一點說是定義了程式執行的次序。注意,為了獲得較好的執行效能,

Java記憶體模型並沒有限制執行引擎使用處理器的暫存器或者快取記憶體來提升指令執行速度,也沒有限制編譯器對指令進行重排序。

也就是說,在java記憶體模型中,也會存在快取一致性問題和指令重排序的問題。

Java記憶體模型規定所有的變數都是存在主存當中(類似於前面說的實體記憶體),每個執行緒都有自己的工作記憶體(類似於前面的快取記憶體)。

執行緒對變數的所有操作都必須在工作記憶體中進行,而不能直接對主存進行操作。並且每個執行緒不能訪問其他執行緒的工作記憶體。

相關推薦

10031---Java併發程式設計volatile關鍵字解析

i = 9; 假若一個執行緒執行到這個語句時,我暫且假設為一個32位的變數賦值包括兩個過程:為低16位賦值,為高16位賦值。 那麼就可能發生一種情況:當將低16位數值寫入之後,突然被中斷,而此時又有一個執行緒去讀取i的值,那麼讀取到的就是錯誤的資料。 2.可見性 可見性是指當多個執行緒訪問同一個變數時,一個

Java併發程式設計volatile關鍵字解析--轉自http://www.cnblogs.com/dolphin0520/p/3920373.html

Java併發程式設計:volatile關鍵字解析    volatile這個關鍵字可能很多朋友都聽說過,或許也都用過。在Java 5之前,它是一個備受爭議的關鍵字,因為在程式中使用它往往會導致出人意料的結果。在Java 5之後,volatile關鍵字才得以重獲生機。   volatile關鍵

【轉】Java併發程式設計volatile關鍵字解析

volatile這個關鍵字可能很多朋友都聽說過,或許也都用過。在Java 5之前,它是一個備受爭議的關鍵字,因為在程式中使用它往往會導致出人意料的結果。在Java 5之後,volatile關鍵字才得以重獲生機。   volatile關鍵字雖然從字面上理解起來比較簡單,但

Java併發程式設計volatile關鍵字解析

volatile這個關鍵字可能很多朋友都聽說過,或許也都用過。在Java 5之前,它是一個備受爭議的關鍵字,因為在程式中使用它往往會導致出人意料的結果。在Java 5之後,volatile關鍵字才得以重獲生機。   volatile關鍵字雖然從字面上理解起來比較簡單,但是要

Java併發程式設計volatile關鍵字解析-原子性,可見性,有序性

volatile這個關鍵字可能很多朋友都聽說過,或許也都用過。在Java 5之前,它是一個備受爭議的關鍵字,因為在程式中使用它往往會導致出人意料的結果。在Java 5之後,volatile關鍵字才得以重獲生機。   volatile關鍵字雖然從字面上理解起來比較簡單,但是要用好不是一件容易的事情

Java併發程式設計裡的volatileJava記憶體模型核CPU記憶體架構的對應關係 Java併發程式設計volatile關鍵字解析

  CPU記憶體架構:https://www.jianshu.com/p/3d1eb589b48e Java記憶體模型:https://www.jianshu.com/p/27a9003c33f4 多執行緒下的快取一致性問題:https://www.jianshu.com/p/97dc5242

Java 併發程式設計 volatile 關鍵字解析

來源:海子 ,www.cnblogs.com/dolphin0520/p/3920373.htmlvolatile這個關鍵字可能很多朋友都聽說過,或許也都用過。在Java 5之前,它是一個備受爭議的關鍵字,因為在程式中使用它往往會導致出人意料的結果。在Java 5之後,vol

Java併發程式設計volatile關鍵字解析(二.併發程式設計中的三個概念)

在併發程式設計中,我們通常會遇到以下三個問題:原子性問題,可見性問題,有序性問題。我們先看具體看一下這三個概念: 1.原子性   原子性:即一個操作或者多個操作 要麼全部執行並且執行的過程不會被任何因素打斷,要麼就都不執行。   一個很經典的例子就是銀行賬戶轉賬問題

2017十年騰訊大牛講解---- Java併發程式設計volatile關鍵字解析

我做為一個工作10年的JAVA從業人員分享一下我的一些經驗,現在解析一下Volatile關鍵詞 volatile這個關鍵字可能很多朋友都聽說過,或許也都用過。在Java 5之前,它是一個備受爭議的關鍵字,因為在程式中使用它往往會導致出人意料的結果。在Java 5之後,

Java併發程式設計volatile關鍵字解析。以及volatile和synchronize的區別

Java併發程式設計:volatile關鍵字解析    volatile這個關鍵字可能很多朋友都聽說過,或許也都用過。在Java 5之前,它是一個備受爭議的關鍵字,因為在程式中使用它往往會導致出人意料的結果。在Java 5之後,volatile關鍵字才得以重獲生

Java併發程式設計volatile關鍵字解析(三)

原文:http://www.cnblogs.com/dolphin0520/p/3920373.html Java併發程式設計:volatile關鍵字解析    volatile這個關鍵字可能很多朋友都聽說過,或許也都用過。在Java 5之前,它是一個備受

Java併發程式設計volatile關鍵字解析(一.記憶體模型的相關概念)

大家都知道,計算機在執行程式時,每條指令都是在CPU中執行的,而執行指令過程中,勢必涉及到資料的讀取和寫入。由於程式執行過程中的臨時資料是存放在主存(實體記憶體)當中的,這時就存在一個問題,由於CPU執行速度很快,而從記憶體讀取資料和向記憶體寫入資料的過程跟CPU執行指令

Java併發程式設計volatile關鍵字解析(轉載)

Java併發程式設計:volatile關鍵字解析    volatile這個關鍵字可能很多朋友都聽說過,或許也都用過。在Java 5之前,它是一個備受爭議的關鍵字,因為在程式中使用它往往會導致出人意料的結果。在Java 5之後,volatile關鍵字才得以重獲生機。   volatile關鍵字雖然

JAVA併發程式設計volatile關鍵字深入解析

生活 天氣賊好的一個禮拜二。 生活就是生下來活下去。 簡述 volatile是JAVA中的一個關鍵字,在JDK1.5以前據說飽受爭議,在程式中使用經常出現一些出入意料的結果。 這個麼,從volatile的翻譯就能看出來,就是不穩定的意思嘛。 JDK1.5以後,volati

Java併發程式設計volatile關鍵字解析

volatile這個關鍵字可能很多朋友都聽說過,或許也都用過。在Java 5之前,它是一個備受爭議的關鍵字,因為在程式中使用它往往會導致出人意料的結果。在Java 5之後,volatile關鍵字才得以重獲生機。   volatile關鍵字雖然從字面上理解起來比較簡單,但是要

JAVA併發程式設計synchronized關鍵字深入解析

生活 天氣賊好的一個禮拜二的吃完晚飯的晚上。 他們去聽課了。 不想寫程式碼。 我在這看點東西吧~ 閒談 對於synchronized的記憶是最早對同步的概念。那時候聊到同步,就會說到StringBuilder和StringBuffer,裡面 的方法都是一樣的,但是StringBu

Java 併發程式設計volatile 關鍵字

作用 保證不同執行緒對 volatile 修飾的變數進行操作時的可見性,即一個執行緒修改了某個變數的值,這新值對其他執行緒來說是立即可見的。 禁止進行指令重排序。 volatile 的可見性 public class Test_09 {

Java併發程式設計volatile關鍵字

volatile這個關鍵字可能很多朋友都聽說過,或許也都用過。在Java 5之前,它是一個備受爭議的關鍵字,因為在程式中使用它往往會導致出人意料的結果。在Java 5之後,volatile關鍵字才得以重獲生機。   volatile關鍵字雖然從字面上理解起來比較簡單,但

Java 併發程式設計volatile的使用及其原理

一、volatile的作用   在《Java併發程式設計:核心理論》一文中,我們已經提到過可見性、有序性及原子性問題,通常情況下我們可以通過Synchronized關鍵字來解決這些個問題,不過如果對Synchronized原理有了解的話,應該知道Synchronized是一

(2.1.27.5)Java併發程式設計Volatile

Java語言提供了一種稍弱的同步機制,即volatile變數,用來確保將變數的更新操作通知到其他執行緒。 當把變數宣告為volatile型別後,編譯器與執行時都會注意到這個變數是共享的,因此不會將該變數上的操作與其他記憶體操作一起重排序。 volatile變數