java volatile變數及其使用場景
java中的一種稍弱的同步機制,就是volatile變數,用於確保將變數的更新操作通知到其他執行緒。
變數宣告為volatile後:
(1)編譯器與執行時都會注意到這個變數是共享的,因此不會將該變數上的操作與其他記憶體操作一起重排序(重排序不懂的,可以自行百度,需要理解)。
(2)volatile變數不會被快取在暫存器或對其他處理器不可見的地方
因此volatile變數總是會返回最新的值。
volatiel是比synchronize關鍵字更輕量級的同步機制,因為它不需要加鎖,也就不會阻塞,所以效能會好點。
這邊為了加深對volatile變數總能返回最新值的理解,你可以這樣想:從記憶體可見性角度來看,寫入volatile相當於推出同步程式碼塊,而讀取volatile變數就相當於進入同步程式碼塊。
注意:並不建議過度依賴volatile變數提供的可見性。如果在程式碼中依賴volatile變數來控制狀態的可見性,通常比使用鎖的程式碼更脆弱,更難理解。
下面我來介紹一下volatile的使用場景,當且僅當滿足以下所有條件時,才應該使用volatile變數:
(1) 對變數的寫入操作不依賴變數的當前值,或者你能確保只有單個執行緒更新變數的值。
(2) 該變數不會與其他狀態變數一起納入不變性條件。
(3) 在訪問變數時不需要加鎖
可能你有點不好理解上面三句話的意思,我們一條一條來講
對於第(1)條的理解就是:一般我們可能有這樣的操作習慣,就是檢查某個狀態以判斷是否退出迴圈,看一下下面這個示例,執行緒試圖通過類似於數綿羊的傳統方法進入休眠狀態。為了使這個示例能正確執行,asleep必須為volatile變數。否則,當asleep被另一個執行緒修改時,執行判斷的執行緒卻發現不了。我們也可以用鎖來確保asleep更新操作的可見性,但這將會使得程式碼變得更復雜。什麼叫 對變數的寫入操作不依賴變數的當前值?就如示例1中decide該函式中對asleep先判斷後執行(執行中保包含了對變數的改變),這種情況下沒使用鎖,所以可能在多執行緒情況下,alseep的記憶體可見性得不到保證。對於這類“對變數的寫入操作依賴變數的當前值”的操作,是需要用鎖進行保護的,此時可以考慮用內建鎖或者顯示鎖,但是方便起見可以使用volatile來保護asleep這個變數。畢竟只是想保護一個變數。解決方式如示例2,當然該示例對上述第三個條件同樣滿足。那條件2中“該變數不會與其他狀態一起納入不變性條件”是什麼意思呢?就是volatile變數不能與其他共享變數做複合操作,volatile變數本身在沒有鎖保護的情況下也不能做複合操作(這是我的理解)。
示例1:
public class NoVolatile { private int sheepCount; private boolean asleep; public void decide() { while (! asleep) { countSomeSheep(); } } public void setAsleep() { asleep = true; } private void countSomeSheep() { if (sheepCount < 1000) { sheepCount++; } else { sheepCount = 0; setAsleep(); } } }
示例2:
class VolatileDemo {
private volatile asleep;
public void decide() {
while (! asleep) {
countSomeSheep();
}
}
public void setAsleep() {
asleep = true;
}
}
對於volatile變數的使用需要有以下注意點:
加鎖機制既可以確保可見性又可以確保原子性,而volatile變數只能確保可見性。啥意思呢,就是,volatile的語義不足以確保遞增操作(count++)的原子性,除非你能確保只有一個執行緒對變數執行寫操作。
相關推薦
java volatile變數及其使用場景
java中的一種稍弱的同步機制,就是volatile變數,用於確保將變數的更新操作通知到其他執行緒。 變數宣告為volatile後: (1)編譯器與執行時都會注意到這個變數是共享的,因此不會將該變數上的操作與其他記憶體操作一起重排序(重排序不懂的,可以自行百度,需要理解)
Java併發程式設計(5):volatile變數修飾符-意料之外的問題(含程式碼)
volatile用處說明在JDK1.2之前,Java的記憶體模型實現總是從主存(即共享記憶體)讀取變數,是不需要進行特別的注意的。而隨著JVM的成熟和優化,現在在多執行緒環境下volatile關鍵字的使用變得非常重要。 在當前的Java記憶體模型下,執行緒可以把變數儲存在本地記憶體(比如機器的暫存器)中,而
java 正確使用 Volatile 變數
轉自:https://www.ibm.com/developerworks/cn/java/j-jtp06197.html Java 語言中的 volatile 變數可以被看作是一種 “程度較輕的 synchronized”;與 synchronized&n
Java 原子變數原理及使用場景
原子變數不使用鎖或其他同步機制來保護對其值的併發訪問。所有操作都是基於CAS原子操作的。他保證了多執行緒在同一時間操作一個原子變數而不會產生資料不一致的錯誤,並且他的效能優於使用同步機制保護的普通變數,譬如說在多執行緒環境 中統計次數就可以使用原子變數。 話不多說看原始碼:
處理器、程序、執行緒、並行、併發、記憶體模型的相關概念、併發程式設計中的三個概念 、Java記憶體模型、剖析volatile關鍵字、用volatile關鍵字的場景
處理器:即中央處理器(CPU,Central Processing Unit),它是一塊超大規模的積體電路,是一臺計算機的運算核心(Core)和控制核心( Control Unit)。它的功能主要是解釋計算機指令以及處理計算機軟體中的資料。 程序:程序(Process)是計算機中的程式關
java volatile關鍵字(及使用場景)
正確使用 volatile 變數的條件 您只能在有限的一些情形下使用 volatile 變數替代鎖。要使 volatile 變數提供理想的執行緒安全,必須同時滿足下面兩個條件: 對變數的寫操作不依賴於當前值。該變數沒有包含在具有其他變數的不變式中。實際上,這些條件表明,可以被寫入 volatile 變數的這
java環境變數配置及其作用
0.jre和jdk jre(java runtime environment) 執行java程式要用的Java執行環境 jdk:java開發人員要用的java開發環境,包括jre 1.JAVA_HOME :JDK安裝目錄。 作用:其他相關環境變數配置可以引
多執行緒讀書筆記二(java記憶體模型、volatile變數、記憶體模型與synchronized、CAS)
java記憶體模型 java中,執行緒之間的通訊是通過共享記憶體的方式,儲存在堆中的例項域,靜態域以及陣列元素都可以線上程間通訊。java記憶體模型控制一個執行緒對共享變數的改變何時對另一個執行緒可見。 執行緒間的共享變數存在主記憶體中,而對於每一個執行緒,都有一個私有的工
Java多執行緒中的volatile變數
首先,volatile的作用是保證記憶體的可見性,但是不能保證操作的原子性。 在Java中記憶體模型中,將記憶體模型分為主記憶體和工作記憶體。 主記憶體是對所有執行緒所共享的,而每個執行緒都有自己的工作記憶體(比如cpu快取,暫存器等等都是一個原理的,都是為了加快讀取速度),工作記憶
Java多執行緒之volatile變數
Java 語言中的 volatile 變數可以被看作是一種 “程度較輕的 synchronized”;與 synchronized 塊相比,volatile 變數所需的編碼較少,並且執行時開銷也較少,但是它所能實現的功能也僅是 synchronized 的一部分。本文介紹了幾種有效使用 volati
Java 基礎系列之volatile變數(一)
一、鎖 兩種特性:互斥性(mutual exclusion)、可見性(visibility)、原子性(atomic) 互斥性就是一次只有一個執行緒可以訪問該共享資料,可見性就是釋放鎖之前,對共享資料的修改,隨後獲取鎖的另一個執行緒是可見的,也就是說一個執行緒修改了共享變數的值,另一個執行緒訪問該共享
深入理解Java虛擬機器筆記---volatile變數的特殊規則
當一個變數定義成volatile之後,它將具備兩種特性:第一是保證此變數對所有執行緒的可見性,這裡的“可見性”是指當一條執行緒修改了這個變數的值,新值對於其它執行緒是可以立即得知的,變數值線上程間傳遞均需要通過主記憶體來完成,如:執行緒A修改一個普通變數的值,然後向主
Java理論與實踐:正確使用volatile變數
之所以將這種技術稱之為“開銷較低的讀-寫鎖”是因為您使用了不同的同步機制進行讀寫操作。因為本例中的寫操作違反了使用volatile的第一個條件,因此不能使用volatile安全地實現計數器——您必須使用鎖。然而,您可以在讀操作中使用volatile確保當前值的可見性,因此可以使用鎖進行所有變化的操作,使用vo
JAVA併發程式設計之Volatile變數
volatile:不穩定的;爆炸性的;反覆無常的volatile變數是java提供的一種弱同步機制(我覺得只能確保讀取的同步),當把變數宣告為volatile型別後: 1.編譯器與執行時都會注意到這個變數是共享的,會變的,不會將該變數上的操作與其他記憶體
Java 理論與實踐: 正確使用 Volatile 變數(轉)
Java 語言中的 volatile 變數可以被看作是一種 “程度較輕的 synchronized”;與synchronized 塊相比,volatile 變數所需的編碼較少,並且執行時開銷也較少,但是它所能實現的功能也僅是 synchronized 的一部分。本文介紹了幾
淺析Java中volatile關鍵字及其作用
在 Java 多執行緒中如何保證執行緒的安全性?那我們可以使用 Synchronized 同步鎖來給需要多個執行緒訪問的程式碼塊加鎖以保證執行緒安全性。使用 synchronized 雖然可以解決多執行緒安全問題,但弊端也很明顯:加鎖後多個執行緒需要判斷鎖,較為消耗資源。所以
Java併發程式設計-volatile變數
併發程式設計時,Java 的volatile提供了一種弱的執行緒同步機制。 volatile提供了兩種語義: 1)禁止編譯器對其修飾的程式碼進行重組 2)將變數的寫操作立即同步到記憶體中而
【Java併發程式設計】之五:volatile變數修飾符—意料之外的問題(含程式碼)
示例程式 下面給出一段程式碼,通過其執行結果來說明使用關鍵字volatile產生的差異,但實際上遇到了意料之外的問題: public class Volatile extends Object implements Runnable { //value變數沒有被標記為volatile private
Java中的static和volatile變數的區別?
在java中宣告一個靜態變數,意味著只有一個副本,無論建立了多少個類的物件,即使沒有建立物件,變數也可以訪問,但是執行緒可能具有本地快取的值。 當變數volatile而不是靜態時,每個object都有一
java volatile關鍵字作用及使用場景
1. volatile關鍵字的作用:保證了變數的可見性(visibility)。被volatile關鍵字修飾的變數,如果值發生了變更,其他執行緒立馬可見,避免出現髒讀的現象。如以下程式碼片段,isShutDown被置為true後,doWork方法仍有執行。如用volatile修飾isShutDo