局部變量保證線程安全

局部變量保證線程安全

首先來看String這個類的hashcode方法盏触,如下

public int hashCode()
{
    int h = hash; /* 代碼① */
    if ( h == 0 && value.length > 0 )
    {
        char val[] = value;
 
        for ( int i = 0; i < value.length; i++ )
        {
            h = 31 * h + val[i];
        }
        hash = h;       /* 代碼② */
    }
    return(h);              /* 代碼③ */
}

hashString類的一個屬性愉耙,可以看到這邊首先是代碼①讀取了本地屬性的值贮尉,并且賦值給局部變量h。并且使用h進行了業(yè)務(wù)邏輯的判斷朴沿。如果h沒有值的話猜谚,就進行 Hash 值的生成,并且賦值到h上悯仙,并且在代碼②處賦值給了屬性hash龄毡。最終返回的,也是局部變量h的值锡垄。那么上述的代碼能否修改為下面的模式

public int hashCode()
{
    if ( hash == 0 && value.length > 0 )  /* 代碼① */
    {
        char    val[]    = value;
        int    h    = 0;
        for ( int i = 0; i < value.length; i++ )
        {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return(hash); /* 代碼② */
}

修改的代碼沒有局部變量沦零,直接使用屬性本身來操作。

答案是否定的货岭,因為這種寫法是線程不安全的路操,可能導(dǎo)致方法的返回值是 0 疾渴。似乎有點費解,因為如果hash值為0 屯仗,則代碼會進入循環(huán)體搞坝,對hash值進行更新。所以乍看之下魁袜,無論如何是不會返回 0 的桩撮。

上述的理解邏輯,在單線程環(huán)境下峰弹,是正確的店量。但是這段代碼工作在多線程環(huán)境。實際上鞠呈,上述代碼有兩次對hash值的讀取融师,分別是代碼①和②∫狭撸可能會出現(xiàn)一種情況旱爆,在代碼①處,讀取到hash值不為 0 窘茁,在代碼②處怀伦,讀取到hash值為0,并且以此為結(jié)果返回了庙曙。顯然此時這種結(jié)果是錯誤的空镜。

要理解這種場景的發(fā)生需要從 JMM 的規(guī)則談起。首先捌朴,兩個讀取之間是沒有因果關(guān)系的吴攒,因此不存在第一個對變量的讀取觀察到了值,第二個對該變量的讀取也要觀察到這個值砂蔽。其次洼怔,在 JMM 中,對一個變量的讀取操作允許其觀察最后一次到對該變量的寫入左驾,只要沒有 HB 關(guān)系來阻止這個讀取的觀察效果镣隶。此外,對象屬性的默認值也是由寫入動作觸發(fā)的诡右。這意味著對hash值的寫入有兩個地方安岂,一個在于對象構(gòu)造時,一個在于其他線程對hash值的寫入帆吻。由于這兩個寫入沒有 HB 關(guān)系域那,因此對hash的讀取可能讀取到任意一個寫入的結(jié)果。所以猜煮,可能會出現(xiàn)的情況是在代碼①處讀取到了其他線程對hash值的寫入次员,因此跳過了內(nèi)部的寫入邏輯败许。而在代碼②處再次讀取hash值,此時讀取到了對象構(gòu)造時對hash默認值的寫入淑蔚,導(dǎo)致返回 0 市殷。

從 JMM 規(guī)則角度是最正確的理解,但是為了形象的想象這一切如何發(fā)生刹衫,我們可以將上面的程序修改如下

public int hashCode()
{
    int a = hash;
    if ( hash == 0 && value.length > 0 ) /* 代碼① */
    {
        char    val[]    = value;
        int    h    = 0;
        for ( int i = 0; i < value.length; i++ )
        {
            h = 31 * h + val[i];
        }
        a = hash = h;
    }
    return(a); /* 代碼② */
}

實際上醋寝,這的確是在執(zhí)行代碼邏輯的時候,一種可能的代碼重排序變種带迟。假定一開始hash值為0甥桂,則a為 0 。在if判斷的時候邮旷,hash讀取到了其他線程寫入的值,因此沒有執(zhí)行計算邏輯蝇摸,最終返回了a的值婶肩,也就是 0 。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末貌夕,一起剝皮案震驚了整個濱河市律歼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌啡专,老刑警劉巖险毁,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異们童,居然都是意外死亡畔况,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進店門慧库,熙熙樓的掌柜王于貴愁眉苦臉地迎上來跷跪,“玉大人,你說我怎么就攤上這事齐板〕痴埃” “怎么了?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵甘磨,是天一觀的道長橡羞。 經(jīng)常有香客問我,道長济舆,這世上最難降的妖魔是什么卿泽? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮吗冤,結(jié)果婚禮上又厉,老公的妹妹穿的比我還像新娘九府。我一直安慰自己,他們只是感情好覆致,可當(dāng)我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布侄旬。 她就那樣靜靜地躺著,像睡著了一般煌妈。 火紅的嫁衣襯著肌膚如雪儡羔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天璧诵,我揣著相機與錄音汰蜘,去河邊找鬼。 笑死之宿,一個胖子當(dāng)著我的面吹牛族操,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播比被,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼色难,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了等缀?” 一聲冷哼從身側(cè)響起枷莉,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎尺迂,沒想到半個月后笤妙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡噪裕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年蹲盘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膳音。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡辜限,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出严蓖,到底是詐尸還是另有隱情薄嫡,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布颗胡,位于F島的核電站毫深,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏毒姨。R本人自食惡果不足惜哑蔫,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闸迷,春花似錦嵌纲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至今阳,卻和暖如春师溅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盾舌。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工墓臭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人妖谴。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓窿锉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親膝舅。 傳聞我的和親對象是個殘疾皇子榆综,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,566評論 2 349

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

  • 本系列出于AWeiLoveAndroid的分享,在此感謝铸史,再結(jié)合自身經(jīng)驗查漏補缺,完善答案怯伊。以成系統(tǒng)琳轿。 Java基...
    濟公大將閱讀 1,524評論 1 6
  • 以上代碼會重復(fù)運行 , 不會停止耿芹。 JMM(java內(nèi)存模型) 若想學(xué)習(xí)好多線程崭篡, 那么必須了解一下JMM Jav...
    尼爾君閱讀 1,747評論 0 2
  • 九種基本數(shù)據(jù)類型的大小,以及他們的封裝類吧秕。(1)九種基本數(shù)據(jù)類型和封裝類 (2)自動裝箱和自動拆箱 什么是自動裝箱...
    關(guān)瑋琳linSir閱讀 1,882評論 0 47
  • java筆記第一天 == 和 equals ==比較的比較的是兩個變量的值是否相等琉闪,對于引用型變量表示的是兩個變量...
    jmychou閱讀 1,488評論 0 3
  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,374評論 0 5