Java并發(fā)編程 - volatile關(guān)鍵解析

volatile關(guān)鍵字可以說是Java虛擬機(jī)提供的最輕量級的同步機(jī)制渠啤,但是它并不容易彎曲被正確壤追、完整的理解撩轰。

volatile的特性

volatile關(guān)鍵字是Java虛擬機(jī)提供的最輕量級的同步機(jī)制坟乾。Java內(nèi)存模型對volatile專門定義了一些特殊的訪問規(guī)則档桃。

當(dāng)一個變量被volatile修飾后枪孩,它將具備兩種特性:

1. 可見性

** 第一是保證此變量對所以線程的可見性** ,這里的"可見性"是指當(dāng)一個線程修改了這個變量的值蔑舞,新值對于其它線程來說是可以立即得知的斗幼。而普通變量不能做到這一點(diǎn),普通變量的值在線程間傳遞均需要通過主內(nèi)存來完成,例如,線程A修改一個普通的變量的值畔咧,然后向主內(nèi)存進(jìn)行回寫,另外一條線程B在線程A回寫完成了之后再從主內(nèi)存進(jìn)行讀取操作拜隧,新變量值才會對線程B可見雀费。

關(guān)于volatile變量的可見性宋光,經(jīng)常會被開發(fā)人員誤解逛漫,認(rèn)為以下描述成立:"volatile變量對所有線程是立即可見,對volatile變量所有的寫操作都能立刻反映到其他線程之中菩暗,換句話說掏熬,volatile變量在各個線程中是一致的,所以基于volatile變量的運(yùn)算在并發(fā)情況下是安全的"。這句話論據(jù)部分并沒有錯履恩,但是其論據(jù)并不能得出"基于volatile變量的運(yùn)算在并發(fā)情況下是安全的"這個結(jié)論。volatile變量在各個線程的工作內(nèi)存中不存在一致性問題(在各個線程的工作內(nèi)存中暇屋,volatile變量也可以存在不一致的情況似袁,但由于每次使用之前都要先刷新,執(zhí)行引擎看不到不一致的情況咐刨,因此可以認(rèn)為不存在一致性問題)昙衅,但是Java里面的運(yùn)算并非是原子操作,導(dǎo)致volatile變量的運(yùn)算在并發(fā)情況下一樣是不安全的定鸟。

例如:

package com.bytebeats.codelab;

import java.util.concurrent.CountDownLatch;

/**
 * ${DESCRIPTION}
 *
 * @author Ricky Fung
 */
public class VolatileDemo {

    public static void main(String[] args) throws InterruptedException {

        VolatileDemo demo = new VolatileDemo();
        demo.run();
    }

    public void run() throws InterruptedException {

        int threadNum = 20;
        final CountDownLatch latch = new CountDownLatch(threadNum);
        for (int i=0; i<threadNum; i++){

            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {

                    for(int x=0; x<50; x++){
                        incr();
                    }
                    latch.countDown();
                }
            });
            t.start();
        }

        //等待所有線程執(zhí)行完累加操作
        latch.await();

        System.out.println(race);
    }

    private volatile int race = 0;

    private void incr(){
        race++;
    }
}

模擬了20個線程對race變量進(jìn)行自增操作而涉,如果這段代碼是并發(fā)安全的話,最后輸出的結(jié)果應(yīng)該為1000联予。但事實上每次運(yùn)行上述代碼啼县,輸出的結(jié)果可能都會不一樣材原,都是一個小于1000的數(shù)。

究其原因季眷,就是Java 中 race++不是原子操作余蟹。

由于volatile變量,只能保證可見性子刮,在不符合以下兩條規(guī)則的情況下威酒,我們?nèi)匀恍枰ㄟ^加鎖(使用synchronized 或 java.util.concurrent中的原子類)來保證原子性。

  • 運(yùn)算結(jié)果并不依賴變量的當(dāng)前值挺峡,或者能夠確保只有單一的線程修改變量的值葵孤。
  • 變量不需要與其他的狀態(tài)變量共同參與不變約束。

2. 禁止指令重排序優(yōu)化

使用volatile變量的第二個語義是禁止指令重排序優(yōu)化橱赠,

原子性尤仍、可見性、有序性

Java內(nèi)存模型是圍繞著在并發(fā)過程中如何處理 原子性狭姨、可見性和有序性 這3個特征來建立的宰啦。我們來逐個看一下哪些操作實現(xiàn)了這3個特性。

原子性

由Java內(nèi)存模型來直接保證的原子性變量操作包括:read送挑、load绑莺、assign、use惕耕、store和write纺裁,我們大致可以認(rèn)為基本數(shù)據(jù)類型的訪問操作是具備原子性的(例外的是long和double的非原子性協(xié)定)。

如果硬要程序需要一個更大范圍的原子性保證(經(jīng)常會遇到)司澎,Java內(nèi)存模型還提供了synchronized 關(guān)鍵字和Lock欺缘,在synchronized 塊之間的操作也具備原子性。

可見性

可見性是指當(dāng)一個線程修改了這個變量的值挤安,新值對于其它線程來說是可以立即得知這個修改谚殊。

Java內(nèi)存模型是通過在變量修改后將新值同步回主內(nèi)存,在變量讀取前從主內(nèi)存刷新變量值 這種依賴主內(nèi)存作為傳遞媒介的方式來實現(xiàn)可見性的蛤铜,無論是普通變量還是volatile變量都是如此嫩絮,普通變量與volatile變量的區(qū)別是:volatile的特殊規(guī)則保證了新值能立即同步到主內(nèi)存,以及每次使用前立即從主內(nèi)存刷新围肥。因此剿干,可以說volatile保證了多線程操作時 變量的可見性,而普通變量則不能保證這一點(diǎn)穆刻。

除了volatile之外置尔,Java還有兩個關(guān)鍵字能實現(xiàn)可見性,即synchronized和final氢伟。

有序性

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末榜轿,一起剝皮案震驚了整個濱河市幽歼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谬盐,老刑警劉巖甸私,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異设褐,居然都是意外死亡颠蕴,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門助析,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人椅您,你說我怎么就攤上這事外冀。” “怎么了掀泳?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵雪隧,是天一觀的道長。 經(jīng)常有香客問我员舵,道長脑沿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任马僻,我火速辦了婚禮庄拇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘韭邓。我一直安慰自己措近,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布女淑。 她就那樣靜靜地躺著瞭郑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鸭你。 梳的紋絲不亂的頭發(fā)上屈张,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機(jī)與錄音袱巨,去河邊找鬼阁谆。 笑死,一個胖子當(dāng)著我的面吹牛瓣窄,可吹牛的內(nèi)容都是我干的笛厦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼俺夕,長吁一口氣:“原來是場噩夢啊……” “哼裳凸!你這毒婦竟也來了贱鄙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤姨谷,失蹤者是張志新(化名)和其女友劉穎逗宁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梦湘,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞎颗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捌议。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哼拔。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瓣颅,靈堂內(nèi)的尸體忽然破棺而出倦逐,到底是詐尸還是另有隱情,我是刑警寧澤宫补,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布檬姥,位于F島的核電站,受9級特大地震影響粉怕,放射性物質(zhì)發(fā)生泄漏健民。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一贫贝、第九天 我趴在偏房一處隱蔽的房頂上張望秉犹。 院中可真熱鬧,春花似錦平酿、人聲如沸凤优。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽筑辨。三九已至,卻和暖如春幸逆,著一層夾襖步出監(jiān)牢的瞬間棍辕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工还绘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留楚昭,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓拍顷,卻偏偏與公主長得像抚太,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

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