第一章
線程共享進程范圍內的資源,但每個線程都有各自的程序計數器、棧以及局部變量等。
多個線程可以同時調度到多個CPU上運行。
線程的優勢?
在服務應用程序中,可以提升資源利用率以及系統吞吐率,發揮多處理器的強大功能。
線程的優先級 執行時間 線程切換需要額外的開銷
第二章
如果多個線程訪問同一個可變的狀態變量是沒有使用合適的同步,那么程序就會出現錯誤,有以下三種方法修復這種問題。
1、不在線程之間共享該狀態變量
2、將狀態變量改為不可變的變量
3、在訪問狀態變量時使用同步
什么是線程安全?自己百度
無狀態對象一定是線程安全的
注意count++這類操作的問題:不是原子的,實際上是三部操作 讀取-修改-寫入
什么是競態條件?
在並發編程中,由於不恰當的執行時序從而使得結果變得不可靠。常見的競態條件類型就是“先檢查后執行”
,例如常見的對象懶加載
一個包:java.concurrent.atomic
內置鎖:加鎖機制,java中用於確保原子性的內置機制。同步代碼塊、同步方法
以synchronized來修飾的方法叫同步方法,該同步代碼塊的鎖就是方法調用所在的對象,靜態的
synchronized方法以Class對象作為鎖
每個java對象都可以用作實現一個同步的鎖,稱為內置鎖或監視器鎖。
線程在進入同步代碼塊前會自動獲得鎖,並且在退出同步代碼塊時自動釋放鎖。
內置鎖是可重入的。
理解一句話:狀態變量是由這個鎖保護的。
鎖不要濫用,同步代碼塊太大會引起不良並發,大大拉低程序性能。當執行較長的計算或者可能無法快速完成的操作時(如網絡I/O、控制台I/O),一定不要持有鎖。
第三章
同步機制不只是為了實現原子性或者確定“臨界區”,還確保了多個線程之間對內存操作的可見性。
加鎖的含義不僅僅局限於互斥行為,還包含內存可見性。
注意重排序現象
最低安全性:當線程在沒有進行同步的情況下讀取變量時,可能會的到一個時效值,但至少這個值是由之前某個線程設置的,而不是一個隨機值。
非volatile類型的64位數值變量(double和long)不適用於最低安全性,因為JVM允許將64位的讀操作或寫操作分解為兩個32位的操作
一種稍弱的同步機制,即volatile變量。
加鎖機制即可以確保可見性又可以確保原子性,而volatile變量只能確保可見性。(確保只有單個線程更新變量的值時可以用
volatile變量 )
發布一個對象
意思是指,是對象能夠在當前作用域之外的代碼中使用。
逸出
當某個不應該發布的對象被發布時,被稱為逸出。
發布對象的方式:
發布對象最簡單的方法是將對象的引用保存到一個公有的靜態變量中。
從非私有的方法中返回一個對象的引用,如java web開發中常用的get set方法。
發布一個內部類的實例(內部類實例包含外部類實例的引用)
不要在構造過程中使用this引用逸出(只有在構造函數返回時,this引用才應該從線程中逸出)
線程封閉
如果在單線程內訪問數據,就不需要同步。這種技術稱為線程封閉。
實現線程封閉的方法:
Ad-hoc線程封閉(了解)
棧封閉(在方法內的局部變量訪問對象,熟悉)
ThreadLocal類(常用)
ThreadLocal類
這個類能使線程中的某個值與保存值的對象關聯起來。該類提供get與set等訪問接口或方法,這些方法為每個使用該變量的線程都存有一份獨立副本,因此get總是返回當前線程在調用set時設置的最新值。當線程終止后,這些值會作為垃圾回收。
不可變對象一定是線程安全的
滿足以下條件時,對象才是不可變的:
對象創建以后其狀態就不可以修改
對象的所有域都是final類型
對象是正確創建的(創建對象時,this引用沒有逸出)