1.Java線程間通信對程式員透明,但是其記憶體可見性問題會引發其他怪異的問題; 2.在並法編程中,需要考慮兩個關鍵問題:1.線程間如何通信 2.線程間如何同步 3.在命令式編程中,線程之間的通信有兩種:1.共用記憶體 2.消息傳遞 4.共用記憶體->線程之間共用程式的公共狀態,通過讀—寫該記憶體中公共狀態
1.Java線程間通信對程式員透明,但是其記憶體可見性問題會引發其他怪異的問題;
2.在並法編程中,需要考慮兩個關鍵問題:1.線程間如何通信 2.線程間如何同步
3.在命令式編程中,線程之間的通信有兩種:1.共用記憶體 2.消息傳遞
4.共用記憶體->線程之間共用程式的公共狀態,通過讀—寫該記憶體中公共狀態進行隱式通信
5.消息傳遞->線程之間沒有公共狀態,線程之間必須通過發送消息來顯示的通信;
6.同步是指控制不同線程間操作發生相對順序的機制,在共用記憶體併發模型中,是顯示進行的,程式員需要顯示的指定某個方法或代碼需要線上程之間互斥執行;而消息傳遞併發模型中,由於消息的發送必須在接受前,同步是隱式的...
7.Java採用的共用記憶體模型,但是Java線程間通信是隱式進行的,整個過程對程式員透明,故不了理解隱式的線程通信,會遇到記憶體可見性的問題...
8.Java線程間通信由Java記憶體模型(JMM)控制,JMM決定一個線程對共用變數的寫入何時對另一個線程可見...
9.JMM定義了線程和記憶體之間的抽象關係:線程之間的共用變數存儲在主記憶體(Main Memory),每個線程都有一個私有的本地記憶體(Local Memory),本地記憶體中存儲了該線程以讀、寫的變數副本;
10.其實本地記憶體是JMM抽象出來的一個概念,並不是實際存在的,它涵蓋了緩存、寫緩存區、寄存器和其他硬體和編譯器優化
11.線程A與線程B之間通信,需要經歷的兩個步驟:
a.線程A把本地記憶體A中更新過的共用變數刷新到主記憶體中;
b.線程B到主記憶體中去讀取線程A之前更新過的共用變數。
總結:線程A和B之間通信必須要經過主記憶體,JMM通過控制主記憶體和每個線程本地記憶體之間的交互,來問Java程式員提供記憶體可見性保證...
12.為提高性能,編譯器和處理器通常會對指令做出重排序,重排序又分為下麵3種:
a.編譯器優化重排序,不改變單線程語義的前提下,可以重新安排語句的執行順序;
b.指令級並行的重排序,若不存在數據依賴性,處理器可以改變語句對應機器指令的執行順序;
c.記憶體系統的重排序,由於處理器使用緩存和讀/寫緩衝區,是的載入和存儲會發生亂序
總結:a是編譯器重排序,bc是處理器重排序,對於編譯器,JMM會禁止特定的編譯器重排序(例如:不存在數據依賴時),JMM針對處理器重排序,使用插入特定類型的記憶體屏障(Memory Barriers)
13.常見處理器(x86處理器)只會對Store-Load(Store1先把數據刷新到記憶體,然後在執行後面的裝在指令...)重排序,ARM架構比較奇怪,可能支持Load-Load、Load-Store、Store-Store;
14.happens-before->JSR-133使用該概念來闡述操作之間的記憶體可見性;
15.happens-before規則:
a.程式順序規則:一個線程每個操作,happens-before於該線程之後進行其他操作
b.監視器鎖規則:一個鎖的解鎖,happens-before與隨後對這個鎖再加鎖;
c.volatile變數規則:一個volatile域的寫,happens-before於任意後序對這個volatile域發生讀操作
d.傳遞性:A happens-before B,B happens-before C => A happens-before C;
總結:happens-before就是展示給程式員理解JMM底層重排序的一種規則...
16.as-if-serial->不管怎麼重排,單線程程式的執行結果不能被改變...as-if-serial就是把單線程程式保護了起來