Object.wait()
和 LockSupport.park()
都是用來使當前線程等待的方法,但它們在使用場景和機制上有所不同:
Object.wait()
-
用途:
wait()
方法屬于對象監視器(Monitor)的一部分,通常與synchronized
塊或方法一起使用。當線程調用某個對象的wait()
方法時,它會釋放該對象的鎖,并使自己進入等待狀態,直到其他線程調用該對象的notify()
或notifyAll()
方法喚醒它,此時線程會重新嘗試獲取鎖并繼續執行。 -
位置限制:只能在同步代碼塊或同步方法中調用,因為需要先獲取到對象的監視器鎖。
-
喚醒條件:可以被
notify()
喚醒,意味著有一個或多個等待線程會被喚醒,但具體哪個線程被喚醒是不確定的;也可以被notifyAll()
喚醒,這時所有等待該對象監視器的線程都會進入鎖的競爭狀態。
LockSupport.park()
-
用途:
park()
方法屬于java.util.concurrent.locks.LockSupport
類,它提供了一種低級別的線程阻塞原語。它不需要與特定的鎖關聯,可以在任何地方調用,使得線程阻塞。它通常與unpark()
方法配對使用,后者可以喚醒一個調用了park()
的線程。 -
位置限制:沒有位置限制,可以在任何地方調用,不需要先獲取鎖。
-
喚醒條件:調用
LockSupport.unpark(Thread thread)
方法可以直接喚醒目標線程,更加靈活和精確。它可以喚醒一個特定的線程,而無需競爭或不確定性。 -
線程許可:
park()
和unpark()
是基于每個線程的許可(permit)機制。初始時,每個線程沒有許可,調用unpark()
會給指定線程添加一個許可,即使之前已經調用過unpark()
給該線程添加了許可,再調用也不會造成影響(許可不會累積)。調用park()
時,如果沒有許可,線程會阻塞,如果有許可,則消耗許可并繼續執行。
總結來說,Object.wait()
更適合與同步代碼塊或方法一起使用,與對象的監視器鎖緊密相關,適用于傳統的線程協作場景;而 LockSupport.park()
提供了一種更底層、更靈活的線程阻塞和喚醒機制,適用于更復雜的并發控制邏輯。
下面是分別使用 Object.wait()
和 LockSupport.park()
的簡單示例:
使用 Object.wait() 的例子
public class WaitNotifyExample {public static void main(String[] args) {final Object monitor = new Object();Thread waitingThread = new Thread(new Runnable() {@Overridepublic void run() {synchronized (monitor) {System.out.println(Thread.currentThread().getName() + " 開始等待");try {monitor.wait(); // 等待被喚醒} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 被喚醒");}}}, "WaitingThread");Thread notifierThread = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(2000); // 模擬一些工作} catch (InterruptedException e) {e.printStackTrace();}synchronized (monitor) {monitor.notify(); // 喚醒等待的線程System.out.println(Thread.currentThread().getName() + " 發出了喚醒通知");}}}, "NotifierThread");waitingThread.start();notifierThread.start();}
}
使用 LockSupport.park() 的例子
import java.util.concurrent.locks.LockSupport;public class ParkUnparkExample {public static void main(String[] args) {Thread waitingThread = new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " 開始等待");LockSupport.park(); // 阻塞當前線程System.out.println(Thread.currentThread().getName() + " 被喚醒");}}, "WaitingThread");Thread unparkerThread = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(2000); // 模擬一些工作} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 準備喚醒線程");LockSupport.unpark(waitingThread); // 喚醒指定線程}}, "UnparkerThread");waitingThread.start();unparkerThread.start();}
}
在這兩個例子中,第一個展示了如何使用 Object.wait()
和 notify()
來實現線程間的等待與通知,第二個例子展示了如何使用 LockSupport.park()
和 unpark()
實現類似的線程控制功能,但更為靈活和獨立于特定鎖。