什麼是監視器(Monitor)? 在Java中,監視器(Monitor)是用來實現線程同步的一種機制。每個Java對象都有一個與之關聯的監視器,線程可以通過synchronized關鍵字來獲取和釋放對象的監視器。監視器的主要作用是確保在同一時刻只有一個線程可以執行同步塊或同步方法,從而實現線程的互斥 ...
什麼是監視器(Monitor)?
在Java中,監視器(Monitor)是用來實現線程同步的一種機制。每個Java對象都有一個與之關聯的監視器,線程可以通過synchronized
關鍵字來獲取和釋放對象的監視器。監視器的主要作用是確保在同一時刻只有一個線程可以執行同步塊或同步方法,從而實現線程的互斥訪問。
監視器的組成部分
監視器通常包含以下三個關鍵部分:
- 入口集(Entry Set):等待獲取監視器鎖的線程集合。
- 所有者線程(Owner Thread):當前持有監視器鎖的線程。
- 等待集(Wait Set):調用了
wait()
方法併進入等待狀態的線程集合。
線程等待的地方
- 入口集(Entry Set):線程在嘗試進入同步塊或同步方法時,如果無法獲取監視器鎖,它們會進入入口集等待。這些線程處於阻塞狀態,等待獲取監視器鎖。
- 等待集(Wait Set):線程在調用
wait()
方法後,會釋放監視器鎖併進入等待集。這些線程處於等待狀態,直到被其他線程通過notify()
或notifyAll()
方法喚醒。
線程狀態轉換示意圖
以下是線程在不同狀態之間轉換的過程示意圖:
- 新建狀態(New):線程被創建,但尚未啟動。
- 可運行狀態(Runnable):線程已經啟動,可以運行但不一定正在運行。
- 阻塞狀態(Blocked):線程在入口集中,等待獲取監視器鎖。
- 等待狀態(Waiting):線程在等待集中,等待其他線程通過
notify()
或notifyAll()
喚醒。 - 超時等待狀態(Timed Waiting):線程在等待集中,等待特定時間後被喚醒。
- 終止狀態(Terminated):線程已經結束執行。
示例代碼解釋
我們通過一個示例代碼來解釋線程在不同狀態之間的轉換:
public class MonitorExample {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("Thread 1: Acquired lock, entering wait state.");
lock.wait();
System.out.println("Thread 1: Woken up, reacquired lock.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2: Acquired lock, notifying.");
lock.notify();
System.out.println("Thread 2: Notified, releasing lock.");
}
});
thread1.start();
try {
Thread.sleep(100); // Ensure thread1 starts first and enters wait state
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
thread2.start();
}
}
過程解釋
-
Thread 1 獲取監視器鎖:
Thread 1
進入同步塊並獲取監視器鎖。- 調用
lock.wait()
方法,Thread 1
釋放監視器鎖併進入等待集。
-
Thread 2 獲取監視器鎖:
Thread 2
進入同步塊並獲取監視器鎖(此時Thread 1
已在等待集)。- 調用
lock.notify()
方法,喚醒等待集中的一個線程(即Thread 1
)。
-
Thread 2 釋放監視器鎖:
Thread 2
退出同步塊,釋放監視器鎖。
-
Thread 1 重新獲取監視器鎖:
- 被喚醒的
Thread 1
從等待集中移動到鎖池,重新競爭獲取監視器鎖。 Thread 1
成功獲取監視器鎖後,從wait()
方法返回,繼續執行後續代碼。
- 被喚醒的
總結
- 監視器(Monitor):用於實現線程同步,每個Java對象都有一個監視器。
- 入口集(Entry Set):線程在嘗試進入同步塊或同步方法時,如果無法獲取監視器鎖,會進入入口集等待。
- 等待集(Wait Set):線程在調用
wait()
方法後,會釋放監視器鎖併進入等待集,等待被喚醒。 - 狀態轉換:線程在不同狀態之間轉換,包括新建、可運行、阻塞、等待、超時等待和終止狀態。