線程可見性

談到多線程,天然就扯到數據爭用,也就天然轉到對線程可見性的學習。多線程

關鍵字

可見性:指的就是一個線程對共享變量的修改,可以及時被其餘線程看到。性能

共享變量:若是一個變量在多個線程的工做內存中都存在副本,那麼這個變量就是這幾個線程的共享變量。學習

重排序:代碼書寫的順序和實際執行的順序可能不一樣,指令重排序是編譯器或處理器爲了提升程序性能而作的優化優化

  • 編譯器優化的重排序
  • 指令集並行重排序
  • 內存系統重排序

as-if-serial 指的是,不管如何重排序,程序執行的結果應該與代碼順序執行的結果一致。 Java編譯器、運行時和處理器都會保證Java在單線程下遵循as-if-serial語義線程

Java內存模型(Java Memory Model):描述了Java程序中各類變量(線程共享變量)的訪問規則,以及在JVM中將變量存儲到內存和從內存中讀取出變量這樣的底層細節。排序

  • 全部的變量都存儲在主內存中
  • 每一個線程都有本身獨立的工做內存,裏面保存該線程使用到的變量的副本
  • 線程對共享變量的全部操做,都必須在本身的工做內存中進行,不能直接從主內存中讀寫
  • 不一樣線程之間沒法直接訪問其餘線程工做內存中的變量,線程簡變量的傳遞須要經過主內存來實現

JMM

致使共享變量在線程間不可見的緣由

  • 線程的交叉執行
  • 重排序結合線程交叉執行
  • 共享變量共享後的值沒能在工做內存和主內存之間即便更新

要實現共享變量的可見性,必須保證兩點

  • 線程修改後的共享變量值可以及時從工做內存刷新到主內存
  • 其餘線程能及時把共享變量的最新值從主內存更新到本身的工做內存中 Java從語言層面支持的可見性實現方式
  • synchronized
  • volatile

synchronized

synchronized用於實現原子性(同步)和可見性。 JMM關於synchronized的兩條規定圖片

  • 線程解鎖前,必須把共享變量的最新值刷新到主內存中
  • 線程加鎖前,將清空工做內存中共享變量的值,從而使用共享變量時須要從主內存中從新讀取最新的值。(注意:加鎖和解鎖必須是同一把鎖) 因而可知,線程解鎖前對共享變量的修改在下次加鎖時對其餘線程是可見的。而synchronized的原子性,也就是鎖,保證了線程不會在共享變量交叉執行,從而避免了可見性的問題。

volatile

  • 可以保證volatile變量的可見性
  • 不能保證volatile變量複合操做的原子性 深刻來講,volatile經過加入內存屏障和禁止重排序優化來實現可見性
  • 寫操做時,會在寫操做以後加入一條store屏障指令
  • 讀操做時,虎仔讀操做以後加入一條load屏障指令 volatile變量的每次讀寫,都必須向主內存提交或更新,這樣便實現了可見性。複合操做指的是num++這樣的操做,先+1後賦值,若是線程交叉執行,頗有可能就會出現未可見的問題。 使用場合
  • 對變量的寫入操做並不依賴其當前值:boolean
  • 改變量沒有包含在具備其餘變量的不變式中:不知足 low<up
相關文章
相關標籤/搜索