在Java中,wait、notify
方法通常與synchronized
關鍵字一起使用,這樣做有幾個重要的原因,主要涉及線程的協調和正確的并發控制。以下是一些關鍵點:
-
監視器鎖(Monitor Lock):
- 每個對象在Java中都可以作為一個監視器鎖,用來管理對該對象的同步訪問。當一個線程持有一個對象的監視器鎖時,其他線程無法同時獲取這個鎖。
wait
方法必須在持有監視器鎖的情況下調用,也就是說,wait
方法必須在synchronized
塊或synchronized
方法中調用。調用wait
方法的線程會放棄該對象的監視器鎖,同時進入等待狀態,直到另一個線程調用同一對象上的notify
或notifyAll
方法。
-
釋放鎖和等待:
- 當一個線程調用對象的
wait
方法時,它會釋放該對象的監視器鎖,并等待被喚醒。如果沒有synchronized
關鍵字保證線程在調用wait
方法時已經持有鎖,就無法確保線程在進入等待狀態前不會與其他線程發生競爭條件(race condition)。 - 只有持有監視器鎖的線程才能調用
wait
方法,這樣可以確保在進入等待狀態之前不會有其他線程修改共享資源,從而避免不一致的狀態。
- 當一個線程調用對象的
-
線程協調:
wait
、notify
和notifyAll
方法提供了一種線程間通信的機制,使得一個線程可以通過這些方法來通知其他線程某些條件已經滿足。synchronized
關鍵字確保了只有一個線程能夠在某個時間段內執行持有相同監視器鎖的代碼,從而避免多個線程同時修改共享資源導致的數據不一致問題。
簡而言之,wait
方法需要與synchronized
一起使用,以確保線程在進入等待狀態之前,已經安全地獲取了監視器鎖,并且在被喚醒后能夠重新獲得鎖。這種機制確保了線程間的協調和共享資源的一致性。
舉個簡單的例子說明:
class SharedResource {private boolean condition = false;public synchronized void waitForCondition() throws InterruptedException {while (!condition) {wait();}// do something after condition is true}public synchronized void changeCondition() {condition = true;notify(); // or notifyAll();}
}
在這個例子中,waitForCondition
方法使用synchronized
關鍵字來獲取鎖,然后調用wait
方法。當changeCondition
方法改變條件并調用notify
或notifyAll
方法時,等待的線程將被喚醒并繼續執行,同時它們會重新獲取鎖。
再寫一段代碼
/*** 功能描述: Java多線程中的 wait() 和 notify() 方法* @author Songxianyang* @date 2024-06-25 17:38*/
public class WaitNotify {public void waitTest(Object lock) throws InterruptedException {synchronized (lock) {lock.wait();System.out.println("線程等待!!!釋放鎖等待----"+Thread.currentThread().getName());}}@SneakyThrowsprivate void notifyTest(Object lock) {synchronized (lock) {// lock.notify();lock.notifyAll();System.out.println("喚醒線程呀哈哈哈---(喚醒其中一個線程,去槍鎖)"+Thread.currentThread().getName());TimeUnit.SECONDS.sleep(2);}}public static void main(String[] args) {Object lock = new Object();Thread thread = new Thread(()->{WaitNotify waitNotify = new WaitNotify();try {waitNotify.waitTest(lock);} catch (InterruptedException e) {e.printStackTrace();}},"線程1");thread.start();Thread thread2 = new Thread(()->{WaitNotify waitNotify = new WaitNotify();try {waitNotify.waitTest(lock);} catch (InterruptedException e) {e.printStackTrace();}},"線程2");thread2.start();Thread thread3 = new Thread(()->{WaitNotify waitNotify = new WaitNotify();waitNotify.notifyTest(lock);},"線程3");thread3.start();}
}
上面得例子可得:
-
方法notify()也要在同步方法或同步塊中調用,該方法是用來通知那些可能等待該對象的對象鎖的其它線程,對其發出通知notify,并使它們重新獲取該對象的對象鎖。
-
如果有多個線程等待,則有線程調度器隨機挑選出一個呈 wait 狀態的線程。(并沒有 “先來后到”)
-
在notify()方法后,當前線程不會馬上釋放該對象鎖,要等到執行notify()方法的線程將程序執行完,也就是退出同步代碼塊之后才會釋放對象鎖。