一致性
內存模型
每一個線程有一個工作內存和主存獨立
工作內存存放主存中變量的值的拷貝
Happen Before
- 1、程序次序規則:在一個單獨的線程中,按照程序代碼的執行流順序,(時間上)先執行的操作happen—before(時間上)后執行的操作。
- 2、管理鎖定規則:一個unlock操作happen—before后面(時間上的先后順序,下同)對同一個鎖的lock操作。
- 3、volatile變量規則:對一個volatile變量的寫操作happen—before后面對該變量的讀操作。
- 4、線程啟動規則:Thread對象的start()方法happen—before此線程的每一個動作。
- 5、線程終止規則:線程的所有操作都happen—before對此線程的終止檢測,可以通過Thread.join()方法結束、Thread.isAlive()的返回值等手段檢測到線程已經終止執行。
- 6、線程中斷規則:對線程interrupt()方法的調用happen—before發生於被中斷線程的代碼檢測到中斷時事件的發生。
- 7、對象終結規則:一個對象的初始化完成(構造函數執行結束)happen—before它的finalize()方法的開始。
- 8、傳遞性:如果操作A happen—before操作B,操作B happen—before操作C,那么可以得出A happen—before操作C。
當數據從主內存復制到工作存儲時,必須出現兩個動作:第一,由主內存執行的讀(read)操作;第二,由工作內存執行的相應的load操作;當數據從工作內存拷貝到主內存時,也出現兩個操作:第一個,由工作內存執行的存儲(store)操作;第二,由主內存執行的相應的寫(write)操作
每一個操作都是原子的,即執行期間不會被中斷
對於普通變量,一個線程中更新的值,不能馬上反應在其他變量中
如果需要在其他線程中立即可見,需要使用 volatile 關鍵字
CAS(Compare And Swap)
非阻塞同步指令之一,硬件指令集支持。先進行操作,如果有並發操作,則不斷重試直到成功。
final不可變
作用於類、方法、成員變量、局部變量。初始化完成后的不可變對象,其它線程可見。常量不會改變不會因為其它線程產生影響。Final修飾的引用類型的地址不變,同時需要保證引用類型各個成員和操作的線程安全問題。因為引用類型成員可能是可變的。
synchronized同步
作用域代碼塊、方法上。通過線程互斥,同一時間的同樣操作只允許一個線程操作。通過字節碼指令實現。
。
Volatile
-
volatile 修飾的變量的變化保證對其它線程立即可見。
volatile變量的寫,先發生於讀。每次使用volatile修飾的變量個線程都會刷新保證變量一致性。但同步之前各線程可能仍有操作。如:各個根據volatile變量初始值分別進行一些列操作,然后再同步寫賦值。每個線程的操作有先后,當一個最早的線程給線程賦值時,其它線程同步。但這時其它線程可能根據初始值做了改變,同步的結果導致其它線程工作結果丟失。
根據volatile的語意使用條件:運算結果不依賴變量的當前值。
-
volatile禁止指令重排優化。
這個語意導致寫操作會慢一些。因為讀操作跟這個沒關系。
並發包概述
java.util.concurrent 包含許多線程安全、測試良好、高性能的並發構建塊。不客氣地說,創建java.util.concurrent 的目的就是要實現 Collection 框架對數據結構所執行的並發操作。通過提供一組可靠的、高性能並發構建塊,開發人員可以提高並發類的線程安全、可伸縮性、性能、可讀性和可靠性。
此包包含locks,concurrent,atomic 三個包。
Atomic:原子數據的構建。
Locks:基本的鎖的實現,最重要的AQS框架和lockSupport
Concurrent:構建的一些高級的工具,如線程池,並發隊列等。
其中都用到了CAS(compare-and-swap)操作。CAS 是一種低級別的、細粒度的技術,它允許多個線程更新一個內存位置,同時能夠檢測其他線程的沖突並進行恢復。它是許多高性能並發算法的基礎。在 JDK 5.0 之前,Java 語言中用於協調線程之間的訪問的惟一原語是同步,同步是更重量級和粗粒度的。公開 CAS 可以開發高度可伸縮的並發 Java 類。這些更改主要由 JDK 庫類使用,而不是由開發人員使用。
CAS操作都封裝在java 不公開的類庫中,sun.misc.Unsafe。此類包含了對原子操作的封裝,具體用本地代碼實現。本地的C代碼直接利用到了硬件上的原子操作。