線程同步問題引入
Java 多線程編程中,線程同步是極重要面向。常見解決方法:
- 方法簽名加
synchronized
synchronized 代碼塊
- JDK 5
java.util.concurrent.locks.Lock
另可用 JDK 1.2 ThreadLocal 保證更好並發性。本系列詳細討論同步機制並探討 ThreadLocal。
大綱
- 線程的先來後到 — 問題提出:為什麼要同步?機制是什麼?
- 給我一把鎖,我能創造一個規矩 — 傳統同步編程方法
- Lock 來了,大家都讓開 — Java 並發框架 Lock 詳解
- 協作,互斥下的協作 — wait/notify/notifyAll
- 你有我有全都有 — ThreadLocal 解決並發安全
- 總結 — Java 線程安全幾種方法對比
一、線程的先來後到
生活化比喻:餐廳衛生間
衛生間小,僅容一人。如廁者進入鎖門(獲取鎖),其他人必須等待直到門開(釋放鎖)。衛生間=共享資源,如廁者=線程。無門時多人湧入必發生爭執、步驟被打亂、意外結果。有門則各自順利完成不被干擾。這就是「先來後到」。
JVM 中的鎖概念
多線程競爭同一資源時,如何保證不「打架」?同步機制:一旦第一線程進入過程,第二線程必須等待第一線程正常返回並退出,才能開始。關鍵在「鎖」。
JVM 視角的鎖
- JVM 協調兩類線程共享數據:堆中實例變量、方法區中類變量(Java 棧數據屬線程私有,無需協調)
- 每個對象和類邏輯上關聯一個監視器:對象監視器保護實例變量,類監視器保護類變量
- 為實現監視器排他性,JVM 為每對象/類關聯一把鎖:任何時刻只允許一線程擁有
- 線程獲取鎖後,釋放前無其他線程可獲取同數據鎖(鎖住對象=獲取關聯監視器)
- 類鎖用對象鎖實現:載入 class 時建立
java.lang.Class 實例,鎖類時實際鎖其 Class 物件
- 可重入:線程可多次對同一對象上鎖,JVM 維護計數器,獲取+1、釋放-1、歸零完全釋放
- 程式設計師無需手動加鎖,對象鎖是 JVM 內部使用
- 用
synchronized 塊/方法標記監視區域,進入時 JVM 自動鎖對象/類
核心結論
有限資源被多線程共享時,為保證互斥訪問,必須排出先來後到。對象鎖在此扮演關鍵角色。詳情請看系列第二篇。