多線程原理(部分)

volatile

解釋

volatile修飾的變量能夠保證可見性,但不保證原子性,每個線程能夠獲取該變量的最新值。

如何保持可見性

對volatile修飾的詞,程序在編譯的時候,會多一個lock彙編指令如下圖所示:
在這裏插入圖片描述
在這裏插入圖片描述
該lock指令有兩個主要作用:

  • 將當前緩存行的數據回寫到內存中
  • 使其他cpu裏緩存了該內存地址的數據無效(緩存一致性機制)

JMM主要是通過設置內存屏障來禁止指令重排序,下圖是彙編程序中的四種內存屏障類型
在這裏插入圖片描述

屏障類型 說明
LoadLoad Barriers 保證Load1數據的裝載先於Load2及所有後續指令的裝載
StoreStore Barriers 保證Store1數據對其他處理器的可見先於Store2及所有後續存儲指令的存儲
LoadStore Barriers 確保Load1數據裝載先於Store2及所有後續的存儲指令刷新到內存
StoreLoad Barriers 確保Store1數據對其他處理器的可見先於Load2及所有後續裝載指令的裝載

volatile是如何防止指令重排序的:

  • volatile寫操作前面插入一個StoreStore屏障
  • volatile寫操作後面插入一個StoreLoad屏障
  • volatile讀操作後面插入一個LoadLoad屏障
  • volatile讀操作後面插入一個LoadStore屏障

適用場景

在使用volatile時需滿足一下兩個條件:

  • 對變量的寫操作不依賴於當前值
  • 該變量沒有包含在具有其他變量的不變式中
  • 不能保持原子性

volatile和synchronized

  1. 使用區別:volatile只能修飾變量,synchronized只能修飾方法和語句塊
  2. 原子性:synchronized可以保證原子性,volatile不能保證原子性
  3. 可見性:都可以保證可見性,但實現原理不同volatile對變量加了lock,synchronized使用monitorEnter和monitorexit monitor JVM
  4. 有序性:volatile能保證有序,synchronized可以保證有序性,但是代價(重量級)併發退化到串行
  5. 線程阻塞:synchronized會引起線程阻塞,volatitle不會引起線程阻塞

CPU高速緩存

CPU緩存是位於CPU與內存之間的臨時存儲器,它的容量比內存小的多但是交換速度卻比內存要快得多。高速緩存的出現主要是爲了解決CPU運算速度與內存讀寫速度不匹配的矛盾,因爲CPU運算速度要比內存讀寫速度快很多,這樣會使CPU花費很長時間等待數據到來或把數據寫入內存。在緩存中的數據是內存中的一小部分,但這一小部分是短時間內CPU即將訪問的,當CPU調用大量數據時,就可避開內存直接從緩存中調用,從而加快讀取速度。
下圖爲CPU高級緩存層次圖:
在這裏插入圖片描述
在引入CPU告訴緩存後,會伴隨着緩存不一致的情況的出現,針對此問題,在CPU層引入:

  • 總線鎖
  • 緩存鎖

緩存鎖的核心是MESI(緩存一致性協議)

MESI

mesi表是緩存的四種狀態,分別是:
在這裏插入圖片描述

Happen-before規則

  • 程序順序規則,程序代碼順序,書寫在前面的操作先行於書寫在後面的操作,控制流順序不是代碼順序還要考慮分支和循環。
  • 管程鎖定規則,一個unlock操作一定發生在同一個鎖的lock操作之後。
  • volatitle規則,對volatitle操作一定寫一定先於後面的讀操作
    線程啓動規則,start方法先於所有操作
  • 線程終止規則,所有操作都先於線程終止檢查
  • 線程中斷規則,對線程interrupt方法調用先於線程終止檢查到中斷事件發生。
  • 對象終結規則,一個對象的初始化完成,先行發生於它的finalize的方法開始。
  • 傳遞性
  • synchronized監控器鎖
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章