java關(guān)鍵字-volatile

前言
  • java 5之前這個關(guān)鍵字備受爭議切威,java5只有volatile才得以重生
  • 因為volatile和java的內(nèi)存模型有關(guān)(想弄清楚volatile就必須弄清相關(guān)的內(nèi)存模型)
java相關(guān)的內(nèi)存模型的概念
  • 程序運行時臨時數(shù)據(jù)存放在主存(物理內(nèi)存中)
  • cpu 在告訴運作時cpu存在高速緩存
  • 就存在高速緩存和內(nèi)存之間的數(shù)據(jù)交互
  • 問題:數(shù)據(jù)的高并發(fā)同步問題
并發(fā)編程的三個概念
  • 原子性
    一個操作或者多個操作,要么全部執(zhí)行芽死,要么都不執(zhí)行稱為一個程序的原子性

  • 可見性
    多個線程同時訪問一個變量,當一個線程改變了這個變量的值次洼,其他線程能夠立即 看到修改的值

  • 有序性
    程序執(zhí)行的順序按照代碼的編寫順序執(zhí)行(因為在代碼執(zhí)行階段关贵,處理器會對代碼進行重排,但是這并不影響代碼的最終執(zhí)行結(jié)果)

java 內(nèi)存模型

從代碼層面分析前面提的三個概念

  • 分析代碼的原子性操作
x = 10;         //語句1
y = x;         //語句2
x++;           //語句3
x = x + 1;     //語句4

語句1是直接將數(shù)值10賦值給x卖毁,也就是說線程執(zhí)行這個語句的會直接將數(shù)值10寫入到工作內(nèi)存中揖曾。
語句2實際上包含2個操作,它先要去讀取x的值亥啦,再將x的值寫入工作內(nèi)存炭剪,雖然讀取x的值以及 將x的值寫入工作內(nèi)存 這2個操作都是原子性操作,但是合起來就不是原子性操作了翔脱。
同樣的念祭,x++和 x = x+1包括3個操作:讀取x的值,進行加1操作碍侦,寫入新的值粱坤。
所以上面4個語句只有語句1的操作具備原子性。
總結(jié):
java內(nèi)存模型只保證了基本讀取和賦值是原子性操作瓷产,如果要實現(xiàn)更大范圍操作的原子性站玄,可以通過synchronized和lock來實現(xiàn),(因為鎖可以保證同一時刻只有一個線程執(zhí)行該代碼塊濒旦,從而保證了原子性)

  • 可見性
    1傻咖、對于可見性星爪,volatile關(guān)鍵字來保證可見性
    當一個共享變量被volatile修飾時,他會保證修改的值會立即被更新到主存,當有其他線程讀取時谆级,他會去主存內(nèi)從新讀取
    2、而普通的共享變量不能保證可見性匕得,因為不能保證什么時候?qū)懭胫齑?br> 3掠河、利用鎖可以實現(xiàn)變量的可見性,因為在synchronized和lock能保證同一時刻只有一個線程獲取鎖執(zhí)行同步代碼灯节,并且在釋放鎖之前會將變量的修改刷新到朱存當中來保證可見性循头;

  • 有序性
    在java內(nèi)存模型中,允許編譯器和處理器對指令進行重排炎疆,但是重排過程不會影響單線程的執(zhí)行卡骂,卻會影響多線程的并發(fā)執(zhí)行順序
    1、 java中 可以通過volatile關(guān)鍵字來保證有序性
    2形入、當然也可通過synchronized和lock來保證有序性
    3全跨、java 先天存在happens-before原則,

剖析volatile的關(guān)鍵字

一旦一個變量被volatile修飾亿遂,就具備以下兩種含義
1浓若、 保證了不同線程對于這個變量進行操作時的可見性
2盒使、禁止指令重排
注意:維度不能保障原子性,
首先先看個代碼

//線程1
boolean stop = false;
while(!stop){
    doSomething();
}
 
//線程2
stop = true;

很多人都會這么干七嫌,但是這個會不會出錯呢少办?答案是會出錯的,因為線程中的數(shù)據(jù)和全局的數(shù)據(jù)是一樣的嗎诵原?
解決的話 就是在stop 前面添加volatile關(guān)鍵字英妓,他會在線程刷新數(shù)據(jù)的時候立馬改變共享內(nèi)存的數(shù)據(jù)
所以說:volatile無法保證原子性

  • volatile保障原子性?
    無法保障
    如果想保障程序的原子性 可依靠sychronized或者lock 來實現(xiàn)

  • volatile保障可見性

public class Test {
    public volatile int inc = 0;
     
    public void increase() {
        inc++;
    }
     
    public static void main(String[] args) {
        final Test test = new Test();
        for(int i=0;i<10;i++){
            new Thread(){
                public void run() {
                    for(int j=0;j<1000;j++)
                        test.increase();
                };
            }.start();
        }
         
        while(Thread.activeCount()>1)  //保證前面的線程都執(zhí)行完
            Thread.yield();
        System.out.println(test.inc);
    }
}

這串代碼就能保證最后的結(jié)果是10000嗎绍赛?答案也是no
因為雖然說線程在執(zhí)行的時候會立馬更新主存的數(shù)據(jù)蔓纠,但是數(shù)據(jù)的++本身分為兩個步驟,所以無法達到理想效果
1吗蚌、可采用java atomic 包下面的 atomicinteger 的增加來計算
2腿倚、利用synchronized 和 lock 來實現(xiàn)原子性
總結(jié):volatile實現(xiàn)可見性,是一個線程(cpu)的數(shù)據(jù)改變蚯妇,他會更新主存的數(shù)據(jù)改變敷燎,同時他會讓其他線程(cpu)的數(shù)據(jù)失效。

  • volatile保證有序性
    線程中的順序 會以volatile為分界箩言,按順序執(zhí)行
//x硬贯、y為非volatile變量
//flag為volatile變量
 
x = 2;        //語句1
y = 0;        //語句2
volatile flag = true;  //語句3
x = 4;         //語句4
y = -1;       //語句5

分析:1、2是一組 誰在前誰在后不一定
但是一定會在3前陨收,同理饭豹,3肯定在4、5的前面务漩,
4拄衰、5誰在前誰在后不一定

volatile的應(yīng)用場景
  • synchronizd關(guān)鍵字是防止多個線程同時執(zhí)行一段代碼,那么他會很影響程序執(zhí)行的效率饵骨,而volatile關(guān)鍵字在某些方面優(yōu)于synchronized翘悉,但是注意volatile關(guān)鍵字無法替代synchronized關(guān)鍵字的,因為volatile無法保證程序的原子性宏悦,
  • 通常使用volatile有以下2個條件:
    1镐确、對變量的改變不依賴于當前值
    2、對變量的依附不依賴于其他對象
    示例:
volatile boolean flag = false;
 
while(!flag){
    doSomething();
}
 
public void setFlag() {
    flag = true;
}
volatile boolean inited = false;
//線程1:
context = loadContext();  
inited = true;            
 
//線程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);

一般都是作為多線程標記用的

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饼煞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子诗越,更是在濱河造成了極大的恐慌砖瞧,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嚷狞,死亡現(xiàn)場離奇詭異块促,居然都是意外死亡荣堰,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門竭翠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來振坚,“玉大人,你說我怎么就攤上這事斋扰《砂耍” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵传货,是天一觀的道長屎鳍。 經(jīng)常有香客問我,道長问裕,這世上最難降的妖魔是什么逮壁? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮粮宛,結(jié)果婚禮上窥淆,老公的妹妹穿的比我還像新娘。我一直安慰自己巍杈,他們只是感情好祖乳,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著秉氧,像睡著了一般眷昆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上汁咏,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天亚斋,我揣著相機與錄音,去河邊找鬼攘滩。 笑死帅刊,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的漂问。 我是一名探鬼主播赖瞒,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蚤假!你這毒婦竟也來了栏饮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤磷仰,失蹤者是張志新(化名)和其女友劉穎袍嬉,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡伺通,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年箍土,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罐监。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡吴藻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出弓柱,到底是詐尸還是另有隱情沟堡,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布吆你,位于F島的核電站弦叶,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏妇多。R本人自食惡果不足惜伤哺,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望者祖。 院中可真熱鬧立莉,春花似錦、人聲如沸七问。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽械巡。三九已至刹淌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讥耗,已是汗流浹背有勾。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留古程,地道東北人蔼卡。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像挣磨,于是被迫代替她去往敵國和親雇逞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

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