日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

[Java并发编程实战] 共享对象之可见性

發(fā)布時(shí)間:2025/3/21 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [Java并发编程实战] 共享对象之可见性 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

「 ***盛年不重來(lái),一日難再晨,及時(shí)當(dāng)勉勵(lì),歲月不待人。***」  陶淵明

PS: 如果覺(jué)得本文有用的話,請(qǐng)幫忙點(diǎn)贊,留言評(píng)論支持一下哦,您的支持是我最大的動(dòng)力!謝謝啦~

我們已經(jīng)知道同步代碼塊和同步方法可以保證以原子的方式執(zhí)行,其實(shí),同步還有另外一個(gè)重要概念:內(nèi)存可見(jiàn)性。換句話說(shuō),我們不僅希望防止某個(gè)線程正在使用對(duì)象狀態(tài)而另一個(gè)線程同時(shí)在修改狀態(tài),而且希望確保當(dāng)一個(gè)線程修改了對(duì)象的狀態(tài)后,其他線程能夠看到修改后的狀態(tài)。

#可見(jiàn)性 一個(gè)線程對(duì)共享變量值的修改,能夠及時(shí)的被其他線程看到。可見(jiàn)性微妙的,這是因?yàn)榭赡馨l(fā)生錯(cuò)誤的事情總是與直覺(jué)大相徑庭。來(lái)看下面這個(gè)例子和他的執(zhí)行結(jié)果:

public class NoVisibility {private static boolean ready;private static int number;private static class ReaderThread extends Thread {public void run() {while(!ready)Thread.yield();System.out.println(number);}}public static void main(String[] args) {// TODO Auto-generated method stubnew ReaderThread().start();number = 88;ready = true;} }

上面的代碼清單,親測(cè)執(zhí)行的結(jié)果是88。 然而,書(shū)本上的解釋是可能出現(xiàn)錯(cuò)誤的結(jié)果。錯(cuò)誤的結(jié)果有下面兩種情況(我重現(xiàn)不到下面的結(jié)果):

  • NoVisibility 可能會(huì)一直保持循環(huán),因?yàn)閷?duì)讀線程來(lái)說(shuō),主線程寫(xiě)給 ready 的值可能永遠(yuǎn)對(duì)讀線程不可見(jiàn)。
  • NoVisibility 可能會(huì)打印0,因?yàn)樵缭趯?duì) number 賦值之前,主線程就已經(jīng)寫(xiě)入 ready 并使之對(duì)讀線程可見(jiàn),這是一種重排序。
  • 即可親測(cè)沒(méi)有發(fā)生,但是可能會(huì)發(fā)生。為了防止這種現(xiàn)象的發(fā)生,只能通過(guò)對(duì)共享變量進(jìn)行恰當(dāng)?shù)耐健?/p>

    ####Java 內(nèi)存模型(JMM,Java Memory Model) 描述了 java 程序中各種變量(線程共享變量)的訪問(wèn)規(guī)則,以及在 JVM 中將變量存儲(chǔ)到內(nèi)存和從內(nèi)存中讀取出變量的底層細(xì)節(jié)。

    所有變量都存儲(chǔ)在主內(nèi)存中,每個(gè)線程都有自己獨(dú)立的工作內(nèi)存,里面保存該線程使用到的變量副本,即主內(nèi)存中該變量的一份拷貝。

    線程對(duì)共享變量的所有操作必須在自己的工作內(nèi)存,線程間變量值的傳遞需要通過(guò)主內(nèi)存來(lái)完成。

    ####加鎖與可見(jiàn)性 加鎖的含義不僅僅局限于互斥行為,還包括內(nèi)存可見(jiàn)性。為了確保所有線程都能看到共享變量的最新值,所有執(zhí)行讀操作或者寫(xiě)操作都必須在同一個(gè)鎖上同步。

    當(dāng)線程 B 執(zhí)行有鎖保護(hù)的代碼塊時(shí),可以看到線程 A 之前在同一個(gè)同步代碼塊中所有的操作結(jié)果。這就是為啥要求所有線程在同一個(gè)鎖上同步,為了確保某個(gè)線程寫(xiě)入該變量的值對(duì)于其他線程來(lái)說(shuō)是可見(jiàn)的。

    ####非原子的64位操作 JVM 允許將64位的讀操作或?qū)懖僮鞣纸鉃閮蓚€(gè)32位的操作。Java 中的 long 類(lèi)型和 double 類(lèi)型是64位的,所以當(dāng)讀取一個(gè)非 volatile 類(lèi)型的 long 變量時(shí),如果該變量的讀操作和寫(xiě)操作在不同的線程中執(zhí)行,那么很可能會(huì)讀取到某個(gè)值的高32位和另一個(gè)值的低32位。因此,在多線程中使用共享的可變的 long 和 double 類(lèi)型變量時(shí)不安全的,除非用關(guān)鍵字 volatile 來(lái)聲明他們,或者用鎖保護(hù)起來(lái)。

    ####volatile變量 Java 提供了一種稍弱的同步機(jī)制,即 volatile 變量,用來(lái)確保將變量的更新操作通知到其他線程。volatile 變量具有 synchronized 的可見(jiàn)性,但是不具備原子特性。要使 volatile 變量提供理想的線程安全,必須同時(shí)滿足下面兩個(gè)條件:

    • 對(duì)變量的寫(xiě)操作不依賴于自身當(dāng)前值
    • 該變量沒(méi)有包含在具有其他變量的不變式中

    volatile 通常被當(dāng)做標(biāo)識(shí)完成、中斷、狀態(tài)的標(biāo)記使用。典型應(yīng)用如下代碼,檢查狀態(tài)標(biāo)記,以確定是否退出一個(gè)循環(huán)。

    volatile boolean asleep;while(!asleep)countSomeSheep();

    當(dāng)然,上面也可以用鎖,但是會(huì)讓代碼變得復(fù)雜。volatile 變量不會(huì)加鎖,也就不會(huì)引起線程的阻塞,相比 sychronized, 這只是輕量級(jí)的同步機(jī)制。盡管 volatile 也可以用來(lái)標(biāo)識(shí)其他類(lèi)型的狀態(tài)信息,但是要格外小心。比如, volatile 的語(yǔ)義不足以使自增操作(count++)原子化。

    本文原創(chuàng)首發(fā)于微信公眾號(hào) [ 林里少年 ],歡迎關(guān)注第一時(shí)間獲取更新。

    轉(zhuǎn)載于:https://my.oschina.net/seaicelin/blog/1823595

    總結(jié)

    以上是生活随笔為你收集整理的[Java并发编程实战] 共享对象之可见性的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。