1. 程式人生 > >【執行緒知識點】--可見性

【執行緒知識點】--可見性

可見性

  • 可見性:一個執行緒對共享變數的修改,能夠及時的被其它執行緒看到。
  • 共享變數:如果一個變數在多個執行緒的工作記憶體中都存在副本,那麼這個變數就是這幾個執行緒的共享變數。

Java記憶體模型

  • 所有的變數都存貯在主記憶體中
  • 每個執行緒都擁有自己獨立的工作記憶體,裡邊儲存該執行緒使用到的變數副本(主記憶體中該變數的一份拷貝)

兩條規定:

  1. 執行緒對共享變數的所有操作都必須在自己的工作記憶體中進行,不可以直接操作主記憶體
  2. 不同執行緒之間無法直接訪問對方工作記憶體中的共享變數,執行緒之間共享變數的傳遞需要通過主記憶體來完成。

共享變數可見性實現的原理

執行緒1對貢獻變數的修改想要及時被執行緒2看到,那麼必須進行如下兩個步驟:

  1.  把執行緒1的工作記憶體中共享變數的值重新整理到主記憶體中。
  2.  把主記憶體中共享變數的最新值更新到執行緒2的工作記憶體中。

記憶體可見性的實現

synchronized實現可見性

synchronized能夠實現:

  • 原子性(同步,互斥鎖)
  • 可見性

JMM對synchronized的兩條規定:

  1.          執行緒解鎖前,必須把共享變數的最新值重新整理到主記憶體中
  2.          執行緒解鎖時,會將工作記憶體中的值標註為失效,重新加鎖時如果發現值失效,那麼就從主記憶體中重新讀取一次。(注意:這裡指的是同一把鎖

以上兩點實現的效果:

執行緒解鎖前對共享變數的修改,在下次加鎖的時候對其他執行緒可見。

重排序

重排序:程式碼書寫的順序和實際執行的順序不同,指令重排序是編譯器或者是處理器為了提高程式的效能而做的優化。

具體有以下三種:

  1. 編譯器優化的重排序(編譯器優化)
  2. 指令級並行重排序(處理器優化)
  3. 記憶體系統的重排序(處理器優化)

as-if-serial:無論如何重排序,程式執行的結果都應該和程式碼順序執行的結果一致(java編譯器和處理器都會保證java在單執行緒下遵循as-if-serial語義)

int num1 = 1;
int num2 = 2;
int sum = num1 + num2;

單執行緒:第一行和第二行的順序可以重排,但是第三行不能。

  • 重排序不會給單執行緒帶來記憶體可見性的問題
  • 多執行緒中程式交錯執行的時候,重排序就可能會帶來記憶體可見性問題了

 

歡迎關注公眾號~