Android volatile 原理。

在《Java 并發(fā)編程:核心理論》一文中恰矩,我們已經(jīng)提到可見性、有序性及原子性 問題憎蛤,通常情況下我們可以通過 Synchronized 關(guān)鍵字來解決這些個(gè)問題外傅,不過 如果對(duì) Synchonized 原理有了解的話,應(yīng)該知道 Synchronized 是一個(gè)較重量級(jí) 的操作俩檬,對(duì)系統(tǒng)的性能有比較大的影響萎胰,所以如果有其他解決方案,我們通常都 避免使用 Synchronized 來解決問題棚辽。

而 volatile 關(guān)鍵字就是 Java 中提供的另一種解決可見性有序性問題的方案技竟。對(duì)于 原子性,需要強(qiáng)調(diào)一點(diǎn)屈藐,也是大家容易誤解的一點(diǎn):對(duì) volatile 變量的單次讀/ 寫操作可保證原子性的灵奖,如 long 和 double 類型變量,但是并不能保證 i++這種 操作的原子性估盘,因?yàn)楸举|(zhì)上 i++是讀、寫兩次操作骡尽。 volatile 也是互斥同步的一種實(shí)現(xiàn)遣妥,不過它非常的輕量級(jí)。 volatile 的意義攀细? 線程會(huì)一直等待箫踩。 可以嘗試獲得鎖,線程可以不用一直等待 鎖狀態(tài) 無法判斷 可以判斷 鎖類型 可重入 不可中斷 非公平 可重入 可判斷 可公平(兩者皆可) 性能 少量同步 大量同步

  • 防止 CPU 指令重排序 volatile 有兩條關(guān)鍵的語義: 保證被 volatile 修飾的變量對(duì)所有線程都是可見的 禁止進(jìn)行指令重排序 要理解 volatile 關(guān)鍵字谭贪,我們得先從 Java 的線程模型開始說起境钟。如圖所示:


    image.png

    Java 內(nèi)存模型規(guī)定了所有字段(這些字段包括實(shí)例字段、靜態(tài)字段等俭识,不包括局 部變量慨削、方法參數(shù)等,因?yàn)檫@些是線程私有的套媚,并不存在競(jìng)爭(zhēng))都存在主內(nèi)存中缚态, 每個(gè)線程會(huì) 有自己的工作內(nèi)存,工作內(nèi)存里保存了線程所使用到的變量在主內(nèi) 存里的副本拷貝堤瘤,線程對(duì)變量的操作只能在工作內(nèi)存里進(jìn)行玫芦,而不能直接讀寫主 內(nèi)存,當(dāng)然不同內(nèi)存之間也 無法直接訪問對(duì)方的工作內(nèi)存本辐,也就是說主內(nèi)存是 線程傳值的媒介桥帆。
    我們來理解第一句話:
    保證被 volatile 修飾的變量對(duì)所有線程都是可見的 如何保證可見性医增?
    被 volatile 修飾的變量在工作內(nèi)存修改后會(huì)被強(qiáng)制寫回主內(nèi)存,其他線程在使用 時(shí)也會(huì)強(qiáng)制從主內(nèi)存刷新老虫,這樣就保證了一致性叶骨。 關(guān)于“保證被 volatile 修飾的變量對(duì)所有線程都是可見的”,有種常見的錯(cuò)誤理解:

  • 由于 volatile 修飾的變量在各個(gè)線程里都是一致的张遭,所以基于 volatile 變 量的運(yùn)算在多線程并發(fā)的情況下是安全的邓萨。 這句話的前半部分是對(duì)的,后半部分卻錯(cuò)了菊卷,因此它忘記考慮變量的操作是否具有原子性這一問題缔恳。
    舉個(gè)例子:
    private volatile int start = 0;
    private void volatile Keyword() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    start++;
                }
            }
        }; for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(runnable); thread.start();
        } Log.d(TAG, "start = " + start);
    }
image.png

這段代碼啟動(dòng)了 10 個(gè)線程,每次 10 次自增洁闰,按道理最終結(jié)果應(yīng)該是 100歉甚,但是 結(jié)果并非如此。 為什么會(huì)這樣扑眉?
仔細(xì)看一下 start++纸泄,它其實(shí)并非一個(gè)原子操作,簡(jiǎn)單來看腰素,它有兩步:
1聘裁、取出 start 的值,因?yàn)橛?volatile 的修飾弓千,這時(shí)候的值是正確的衡便。
2、自增洋访,但是自增的時(shí)候镣陕,別的線程可能已經(jīng)把 start 加大了,這種情況下就有 可能把較小的 start 寫回主內(nèi)存中姻政。
所以 volatile 只能保證可見性呆抑,在不符合以 下場(chǎng)景下我們依然需要通過加鎖來保證原子性:

  • 運(yùn)算結(jié)果并不依賴變量當(dāng)前的值,或者只有單一線程修改變量的值汁展。(要 么結(jié)果不依賴當(dāng)前值鹊碍,要么操作是原子性的,要么只要一個(gè)線程修改變量 的值) - 變量不需要與其他狀態(tài)變量共同參與不變約束 比方說我們會(huì)在線程里加 個(gè) boolean 變量食绿,來判斷線程是否停止妹萨,這種情況就非常適合使用 volatile。
    我們?cè)賮砝斫獾诙湓挕?禁止進(jìn)行指令重排序 什么是指令重排序炫欺?
    指令重排序是指指令亂序執(zhí)行乎完,即在條件允許的情況下直接運(yùn)行當(dāng)前有能 力立即執(zhí)行的后續(xù)指令,避開為獲取一條指令所需數(shù)據(jù)而造成的等待品洛,通 過亂序執(zhí)行的技術(shù)提供執(zhí)行效率树姨。 指令重排序會(huì)在被 volatile 修飾的變量的賦值操作前摩桶,添加一個(gè)內(nèi)存屏障, 指令重排序時(shí)不能把后面的指令重排序移到內(nèi)存屏障之前的位置帽揪。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末硝清,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子转晰,更是在濱河造成了極大的恐慌芦拿,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件查邢,死亡現(xiàn)場(chǎng)離奇詭異蔗崎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)扰藕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門缓苛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人邓深,你說我怎么就攤上這事未桥。” “怎么了芥备?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵冬耿,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我萌壳,道長(zhǎng)淆党,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任讶凉,我火速辦了婚禮,結(jié)果婚禮上山孔,老公的妹妹穿的比我還像新娘懂讯。我一直安慰自己,他們只是感情好台颠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布褐望。 她就那樣靜靜地躺著,像睡著了一般串前。 火紅的嫁衣襯著肌膚如雪瘫里。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天荡碾,我揣著相機(jī)與錄音谨读,去河邊找鬼。 笑死坛吁,一個(gè)胖子當(dāng)著我的面吹牛劳殖,可吹牛的內(nèi)容都是我干的铐尚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼哆姻,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼宣增!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起矛缨,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤爹脾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后箕昭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體灵妨,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年盟广,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了闷串。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡筋量,死狀恐怖烹吵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情桨武,我是刑警寧澤肋拔,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站呀酸,受9級(jí)特大地震影響凉蜂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜性誉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一窿吩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧错览,春花似錦纫雁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至羞海,卻和暖如春忌愚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背却邓。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工硕糊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓癌幕,卻偏偏與公主長(zhǎng)得像衙耕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子勺远,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

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