[Java] Java中Volatile關鍵字詳解

Java中Volatile關鍵字詳解

原文地址

一饭豹、基本概念
先補充一下概念:Java 內(nèi)存模型中的可見性啦逆、原子性和有序性臀玄。

可見性:

可見性是一種復雜的屬性,因為可見性中的錯誤總是會違背我們的直覺况木。通常垒拢,我們無法確保執(zhí)行讀操作的線程能適時地看到其他線程寫入的值旬迹,有時甚至是根本不可能的事情。為了確保多個線程之間對內(nèi)存寫入操作的可見性求类,必須使用同步機制奔垦。

可見性,是指線程之間的可見性尸疆,一個線程修改的狀態(tài)對另一個線程是可見的椿猎。也就是一個線程修改的結(jié)果。另一個線程馬上就能看到寿弱。比如:用volatile修飾的變量鸵贬,就會具有可見性。volatile修飾的變量不允許線程內(nèi)部緩存和重排序脖捻,即直接修改內(nèi)存阔逼。所以對其他線程是可見的。但是這里需要注意一個問題地沮,volatile只能讓被他修飾內(nèi)容具有可見性嗜浮,但不能保證它具有原子性。比如 volatile int a = 0摩疑;之后有一個操作 a++危融;這個變量a具有可見性,但是a++ 依然是一個非原子操作雷袋,也就是這個操作同樣存在線程安全問題吉殃。

在 Java 中 volatile、synchronized 和 final 實現(xiàn)可見性楷怒。

原子性:

原子是世界上的最小單位蛋勺,具有不可分割性。比如 a=0鸠删;(a非long和double類型) 這個操作是不可分割的抱完,那么我們說這個操作時原子操作。再比如:a++刃泡; 這個操作實際是a = a + 1巧娱;是可分割的,所以他不是一個原子操作烘贴。非原子操作都會存在線程安全問題禁添,需要我們使用同步技術(sychronized)來讓它變成一個原子操作。一個操作是原子操作桨踪,那么我們稱它具有原子性老翘。java的concurrent包下提供了一些原子類,我們可以通過閱讀API來了解這些原子類的用法。比如:AtomicInteger酪捡、AtomicLong叁征、AtomicReference等。

在 Java 中 synchronized 和在 lock逛薇、unlock 中操作保證原子性捺疼。

有序性:

Java 語言提供了 volatile 和 synchronized 兩個關鍵字來保證線程之間操作的有序性,volatile 是因為其本身包含“禁止指令重排序”的語義永罚,synchronized 是由“一個變量在同一個時刻只允許一條線程對其進行 lock 操作”這條規(guī)則獲得的啤呼,此規(guī)則決定了持有同一個對象鎖的兩個同步塊只能串行執(zhí)行。

下面內(nèi)容摘錄自《Java Concurrency in Practice》:

下面一段代碼在多線程環(huán)境下呢袱,將存在問題官扣。

+ View code
/**
 * @author zhengbinMac
 */
public class NoVisibility {
    private static boolean ready;
    private static int number;
    private static class ReaderThread extends Thread {
        @Override
        public void run() {
            while(!ready) {
                Thread.yield();
            }
            System.out.println(number);
        }
    }
    public static void main(String[] args) {
        new ReaderThread().start();
        number = 42;
        ready = true;
    }
}

NoVisibility可能會持續(xù)循環(huán)下去,因為讀線程可能永遠都看不到ready的值羞福。甚至NoVisibility可能會輸出0惕蹄,因為讀線程可能看到了寫入ready的值,但卻沒有看到之后寫入number的值治专,這種現(xiàn)象被稱為“重排序”卖陵。只要在某個線程中無法檢測到重排序情況(即使在其他線程中可以明顯地看到該線程中的重排序),那么就無法確保線程中的操作將按照程序中指定的順序來執(zhí)行张峰。當主線程首先寫入number泪蔫,然后在沒有同步的情況下寫入ready,那么讀線程看到的順序可能與寫入的順序完全相反喘批。

在沒有同步的情況下撩荣,編譯器、處理器以及運行時等都可能對操作的執(zhí)行順序進行一些意想不到的調(diào)整饶深。在缺乏足夠同步的多線程程序中餐曹,要想對內(nèi)存操作的執(zhí)行春旭進行判斷,無法得到正確的結(jié)論粥喜。

這個看上去像是一個失敗的設計凸主,但卻能使JVM充分地利用現(xiàn)代多核處理器的強大性能。例如额湘,在缺少同步的情況下,Java內(nèi)存模型允許編譯器對操作順序進行重排序旁舰,并將數(shù)值緩存在寄存器中锋华。此外,它還允許CPU對操作順序進行重排序箭窜,并將數(shù)值緩存在處理器特定的緩存中毯焕。

二、Volatile原理
  Java語言提供了一種稍弱的同步機制,即volatile變量纳猫,用來確保將變量的更新操作通知到其他線程婆咸。當把變量聲明為volatile類型后,編譯器與運行時都會注意到這個變量是共享的芜辕,因此不會將該變量上的操作與其他內(nèi)存操作一起重排序尚骄。volatile變量不會被緩存在寄存器或者對其他處理器不可見的地方,因此在讀取volatile類型的變量時總會返回最新寫入的值侵续。

在訪問volatile變量時不會執(zhí)行加鎖操作倔丈,因此也就不會使執(zhí)行線程阻塞,因此volatile變量是一種比sychronized關鍵字更輕量級的同步機制状蜗。


這里寫圖片描述

當對非 volatile 變量進行讀寫的時候需五,每個線程先從內(nèi)存拷貝變量到CPU緩存中。如果計算機有多個CPU轧坎,每個線程可能在不同的CPU上被處理宏邮,這意味著每個線程可以拷貝到不同的 CPU cache 中。

而聲明變量是 volatile 的缸血,JVM 保證了每次讀變量都從內(nèi)存中讀蜜氨,跳過 CPU cache 這一步。

當一個變量定義為 volatile 之后属百,將具備兩種特性:

1.保證此變量對所有的線程的可見性记劝,這里的“可見性”,如本文開頭所述族扰,當一個線程修改了這個變量的值厌丑,volatile 保證了新值能立即同步到主內(nèi)存,以及每次使用前立即從主內(nèi)存刷新渔呵。但普通變量做不到這點怒竿,普通變量的值在線程間傳遞均需要通過主內(nèi)存(詳見:Java內(nèi)存模型)來完成。

2.禁止指令重排序優(yōu)化扩氢。有volatile修飾的變量耕驰,賦值后多執(zhí)行了一個“l(fā)oad addl $0x0, (%esp)”操作,這個操作相當于一個內(nèi)存屏障(指令重排序時不能把后面的指令重排序到內(nèi)存屏障之前的位置)录豺,只有一個CPU訪問內(nèi)存時朦肘,并不需要內(nèi)存屏障;(什么是指令重排序:是指CPU采用了允許將多條指令不按程序規(guī)定的順序分開發(fā)送給各相應電路單元處理)双饥。

volatile 性能:

volatile 的讀性能消耗與普通變量幾乎相同媒抠,但是寫操作稍慢,因為它需要在本地代碼中插入許多內(nèi)存屏障指令來保證處理器不發(fā)生亂序執(zhí)行咏花。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末趴生,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苍匆,老刑警劉巖刘急,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異浸踩,居然都是意外死亡叔汁,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門民轴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來攻柠,“玉大人,你說我怎么就攤上這事后裸」迮ィ” “怎么了?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵微驶,是天一觀的道長浪谴。 經(jīng)常有香客問我,道長因苹,這世上最難降的妖魔是什么苟耻? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮扶檐,結(jié)果婚禮上凶杖,老公的妹妹穿的比我還像新娘。我一直安慰自己款筑,他們只是感情好智蝠,可當我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奈梳,像睡著了一般杈湾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上攘须,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天漆撞,我揣著相機與錄音,去河邊找鬼于宙。 笑死浮驳,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的捞魁。 我是一名探鬼主播抹恳,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼署驻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤旺上,失蹤者是張志新(化名)和其女友劉穎瓶蚂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宣吱,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡窃这,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了征候。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杭攻。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖疤坝,靈堂內(nèi)的尸體忽然破棺而出兆解,到底是詐尸還是另有隱情,我是刑警寧澤跑揉,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布锅睛,位于F島的核電站,受9級特大地震影響历谍,放射性物質(zhì)發(fā)生泄漏现拒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一望侈、第九天 我趴在偏房一處隱蔽的房頂上張望印蔬。 院中可真熱鬧,春花似錦脱衙、人聲如沸侥猬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陵究。三九已至,卻和暖如春奥帘,著一層夾襖步出監(jiān)牢的瞬間铜邮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工寨蹋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留松蒜,地道東北人。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓已旧,卻偏偏與公主長得像秸苗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子运褪,可洞房花燭夜當晚...
    茶點故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 從三月份找實習到現(xiàn)在惊楼,面了一些公司玖瘸,掛了不少,但最終還是拿到小米檀咙、百度雅倒、阿里、京東弧可、新浪蔑匣、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,213評論 11 349
  • 天天說絲路,復興中華文化校套,但小伙伴們大多還是只了解一點价脾。今天影小兔就來為大家科普一下,什么才是絲綢之路搔确。 絲綢之路...
    心安處即歸途閱讀 826評論 0 2
  • 煙山澀水淡春妝彼棍, 美景任君描。 鳥鳴紅檐膳算, 蛙聲綠田座硕, 和風淺入眠。 草破新土多蹉跎涕蜂, 歲月有情知华匾。 勿悲莫愁, ...
    夢馬映象閱讀 403評論 14 24
  • 街角的路燈悄然亮起 暮色變的昏暗 走在雪后路上 一步一步机隙,深深的刻印著 不同的形狀蜘拉,不同的大小 但無論怎么去改變 ...
    瀏小煚拓閱讀 936評論 2 4
  • 孕育和孵化。 看到這張卡有鹿,明白自己正處在一個艱難的蛻變期旭旭,看到路途遙遠和前因后果,需要更高的視角更全面的自我認識葱跋,...
    一閃_31de閱讀 371評論 0 0