并發(fā)編程-06線程安全性之可見性 (synchronized + volatile)

      網(wǎng)友投稿 737 2022-05-29

      文章目錄

      線程安全性文章索引

      腦圖

      可見性定義

      導(dǎo)致不可見的原因

      可見性 -synchronized (既保證原子性又保證可見性)

      可見性 - volatile(但不保證操作的原子性)

      volatile變量 寫操作

      volatile變量 讀操作

      使用volatile嘗試解決計數(shù)并發(fā)錯誤的問題 【volatile無法解決該問題】

      volatile使用場景

      synchronized和volatile的比較

      代碼

      線程安全性文章索引

      并發(fā)編程-03線程安全性之原子性(Atomic包)及原理分析

      并發(fā)編程-04線程安全性之原子性Atomic包的4種類型詳解

      并發(fā)編程-05線程安全性之原子性【鎖之synchronized】

      并發(fā)編程-06線程安全性之可見性 (synchronized + volatile)

      并發(fā)編程-07線程安全性之有序性

      腦圖

      可見性定義

      一個線程對共享變量值的修改,能夠及時的被其他線程看到。

      導(dǎo)致不可見的原因

      線程交叉執(zhí)行

      重排序結(jié)合線程交叉執(zhí)行

      共享變量更新后的值沒有在工作內(nèi)存與主內(nèi)存之間及時更新

      結(jié)合我們前面說過的Java內(nèi)存模型,上述三個原因我們就很容易理解了。 不清楚的童鞋可以再回顧下 并發(fā)編程-02并發(fā)基礎(chǔ)CPU多級緩存和Java內(nèi)存模型JMM

      可見性 -synchronized (既保證原子性又保證可見性)

      synchronized能夠?qū)崿F(xiàn)原子性和可見性 。

      JMM中關(guān)于Synchronized的規(guī)定

      線程解鎖前,必須把共享變量的最新值刷新到主內(nèi)存

      線程加鎖時,必須將工作內(nèi)存中的共享變量的值清空,從而使用共享變量時需要從主內(nèi)存中重新讀取最新的值。

      【注意,加鎖和解鎖必須是同一把鎖】

      可見性 - volatile(但不保證操作的原子性)

      volatile可以保證 可見性和 有序性

      并發(fā)編程-06線程安全性之可見性 (synchronized + volatile)

      通過加入內(nèi)存屏障和禁止重排序優(yōu)化來實現(xiàn)。

      對volatile變量寫操作時,會在寫操作后加入一條store屏障指令,將本地內(nèi)存中的共享變量值刷新到主內(nèi)存

      對volatile變量讀操作,會在讀操作前加入一條load指令屏障,從主內(nèi)存中讀取共享變量

      volatile本質(zhì)是在告訴JVM當(dāng)前變量在寄存器中的值是不確定的,使用前,需要先從主存中讀取,因此可以實現(xiàn)可見性。而對n=n+1,n++等操作時,volatile關(guān)鍵字將失效,不能起到像synchronized一樣的線程同步(原子性)的效果。

      volatile變量 寫操作

      volatile變量 讀操作

      使用volatile嘗試解決計數(shù)并發(fā)錯誤的問題 【volatile無法解決該問題】

      即使將count用volatile修飾,每次從主存中取到的都是最新的值,可是當(dāng)多個線程同時取到最新的值,執(zhí)行+1操作,當(dāng)刷新到主存中的時候會覆蓋結(jié)果,從而丟失一些+1操作

      volatile使用場景

      多線程中使用volatile變量,對變量的寫入操作不能依賴當(dāng)前變量的值:如count++ .【 解釋下: count++不是原子操作,因為其可以分為:從主內(nèi)存中讀取count的值,在自己線程的工作內(nèi)存中將count的值+1,寫入最新的count的值到主內(nèi)存。 對于count++,線程A和線程B都執(zhí)行一次,最后輸出的count的值可能是1也可能是2】 。 比較適合 狀態(tài)標(biāo)記 場景

      狀態(tài)標(biāo)記偽代碼

      volatile boolean inited = false; // 線程A context = loadContext(); inited = true; // 線程B while(!inited ){ sleep(); } doSomethingWithConfig(context);

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      將inited 標(biāo)記為 volatile , 當(dāng)線程A更新inited后,因為是volatile,所以線程B可以及時從主內(nèi)存中感知到inited的改變。 這樣就確保了線程B中使用的contex是初始化過的。

      double check (比較常見的比如單例模式中的double check)

      synchronized和volatile的比較

      synchronized保證內(nèi)存可見性和操作的原子性

      volatile只能保證內(nèi)存可見性

      volatile不需要加鎖,比synchronized更輕量級,并不會阻塞線程

      volatile標(biāo)記的變量不會被編譯器優(yōu)化,而synchronized標(biāo)記的變量可以被編譯器優(yōu)化(如編譯器重排序的優(yōu)化).

      volatile是變量修飾符,僅能用于變量,而synchronized是一個方法或塊的修飾符。

      代碼

      https://github.com/yangshangwei/ConcurrencyMaster

      Java 任務(wù)調(diào)度

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:Jupyter工具系列之初識jupyter lab
      下一篇:舊貌換新顏 華為助力甲殼蟲科技打造智慧環(huán)衛(wèi)
      相關(guān)文章
      亚洲爆乳少妇无码激情| 亚洲αⅴ无码乱码在线观看性色| 午夜亚洲av永久无码精品| 亚洲宅男精品一区在线观看| 久久久久亚洲av无码专区喷水| 亚洲αv在线精品糸列| 亚洲人成精品久久久久| 亚洲欧洲美洲无码精品VA | 国产亚洲大尺度无码无码专线 | 亚洲七七久久精品中文国产| 亚洲精品无码激情AV| 亚洲人成人无码网www国产| 亚洲一级特黄大片无码毛片 | 亚洲国产精品日韩在线观看| 亚洲欧洲日产专区| 亚洲天堂一区二区三区| 亚洲人成网网址在线看| 亚洲偷偷自拍高清| 亚洲精品无码av片| 丰满亚洲大尺度无码无码专线| 国产精品亚洲а∨无码播放不卡 | 亚洲日本韩国在线| 曰韩亚洲av人人夜夜澡人人爽| 伊人亚洲综合青草青草久热| 亚洲人成网站在线观看播放| 久久91亚洲精品中文字幕| 老汉色老汉首页a亚洲| 亚洲日本乱码一区二区在线二产线| 亚洲另类视频在线观看| 国产午夜亚洲精品| 亚洲AV永久无码天堂影院 | 亚洲午夜精品一级在线播放放| 久久久青草青青国产亚洲免观 | 国产亚洲视频在线观看网址| 亚洲精品无码久久久久AV麻豆| 亚洲一区二区三区自拍公司| 亚洲成人在线电影| 亚洲中文字幕人成乱码 | 国产精品无码亚洲精品2021| 国产成人亚洲精品影院| 亚洲av无码无在线观看红杏|