<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 如何在 Java 中使用`wait()`,`notify()`和`notifyAll()`? > 原文: [https://howtodoinjava.com/java/multi-threading/wait-notify-and-notifyall-methods/](https://howtodoinjava.com/java/multi-threading/wait-notify-and-notifyall-methods/) [**Java 并發**](https://howtodoinjava.com/java-concurrency-tutorial/ "multithreading in java")是一個非常復雜的主題,在編寫處理在任何給定時間訪問一個/多個共享資源的多個線程的應用程序代碼時,需要引起很多關注。 Java 5 引入了諸如[**`BlockingQueue`**](https://howtodoinjava.com/java/multi-threading/how-to-use-blockingqueue-and-threadpoolexecutor-in-java/ "How to use BlockingQueue and ThreadPoolExecutor in java")和`Executors`之類的類,它們通過提供易于使用的 API 消除了一些復雜性。 使用并發類的程序員會比使用`wait()`,`notify()`和`notifyAll()`方法調用直接處理同步內容的程序員更有信心。 我還將建議您自己通過同步使用這些較新的 API,但是由于種種原因,我們經常需要這樣做,例如維護舊版代碼。 掌握這些方法的豐富知識將在您到達這種情況時為您提供幫助。 在本教程中,我將討論 Java 中`wait() notify() notifyall()`的用途。 我們將了解`wait`和`notify`之間的**區別**。 > 閱讀更多: [Java 中的`wait()`和`sleep()`之間的區別](https://howtodoinjava.com/java/multi-threading/difference-between-sleep-and-wait/) ## 1\. 什么是`wait()`,`notify()`和`notifyAll()`方法? Java 中的`Object`類具有三個最終方法,這些方法允許線程就資源的鎖定狀態進行通信。 1. #### `wait()` 它告訴調用線程放棄鎖定并進入睡眠狀態,直到其他線程進入同一監視器并調用`notify()`為止。 `wait()`方法在等待之前釋放鎖,并在從`wait()`方法返回之前重新獲取鎖。 實際上,`wait()`方法與同步鎖緊密集成在一起,使用的特性無法直接從同步機制獲得。 換句話說,我們不可能僅在 Java 中實現`wait()`方法。 它是**本地方法**。 調用`wait()`方法的常規語法如下: ```java synchronized( lockObject ) { while( ! condition ) { lockObject.wait(); } //take the action here; } ``` 2. #### `notify()` 它喚醒一個在同一對象上調用`wait()`的單個線程。 應該注意的是,調用`notify()`實際上并沒有放棄對資源的鎖定。 它告訴等待的線程該線程可以喚醒。 但是,直到通知者的同步塊完成后才真正放棄鎖定。 因此,如果通知者在資源上調用`notify()`,但通知者仍需要在其同步塊內對該資源執行 10 秒的操作,則一直在等待的線程將至少需要再等待通知者 10 秒,來釋放對象上的鎖定,即使調用了`notify()`。 調用`notify()`方法的常規語法如下: ```java synchronized(lockObject) { //establish_the_condition; lockObject.notify(); //any additional code if needed } ``` 3. #### `notifyAll()` 它將喚醒在同一對象上調用`wait()`的所有線程。 盡管沒有保證,但是在大多數情況下,優先級最高的線程將首先運行。 其他與上述`notify()`方法相同。 調用`notify()`方法的一般語法如下: ```java synchronized(lockObject) { establish_the_condition; lockObject.notifyAll(); } ``` 通常,使用`wait()`方法的線程會確認條件不存在(通常通過檢查變量),然后調用`wait()`方法。 當另一個線程建立條件(通常通過設置相同的變量)時,它將調用`notify()`方法。 等待通知機制未指定特定條件/變量值是什么。 開發人員可以在調用`wait()`或`notify()`之前指定要檢查的條件。 讓我們寫一個小程序來了解**應該如何使用**`wait()`,`notify()`和`notifyall()`方法來獲得理想的結果。 ## 2\. 如何一起使用`wait()`,`notify()`和`notifyAll()`方法 在本練習中,我們將使用`wait()`和`notify()`方法解決**生產者消費者問題**。 為了使程序簡單并專注于`wait()`和`notify()`方法的使用,我們將只涉及一個生產者和一個消費者線程。 該程序的其他特性包括: * 生產者線程每 1 秒鐘產生一個新資源,并將其放入`taskQueue`中。 * 使用者線程需要 1 秒鐘來處理`taskQueue`中消耗的資源。 * `taskQueue`的最大容量為 5,即在任何給定時間,`taskQueue`中最多可以存在 5 個資源。 * 兩個線程都無限運行。 #### 2.1 生產者線程 以下是根據我們的要求生產者線程的代碼: ```java class Producer implements Runnable { private final List<Integer> taskQueue; private final int MAX_CAPACITY; public Producer(List<Integer> sharedQueue, int size) { this.taskQueue = sharedQueue; this.MAX_CAPACITY = size; } @Override public void run() { int counter = 0; while (true) { try { produce(counter++); } catch (InterruptedException ex) { ex.printStackTrace(); } } } private void produce(int i) throws InterruptedException { synchronized (taskQueue) { while (taskQueue.size() == MAX_CAPACITY) { System.out.println("Queue is full " + Thread.currentThread().getName() + " is waiting , size: " + taskQueue.size()); taskQueue.wait(); } Thread.sleep(1000); taskQueue.add(i); System.out.println("Produced: " + i); taskQueue.notifyAll(); } } } ``` * 此處,`produce(counter++)`代碼已在無限循環內編寫,以便生產者以規則的間隔保持生產元素。 * 我們已經按照通用準則編寫了`produce()`方法代碼,以編寫第一部分中提到的`wait()`方法。 * `wait()`完成后,生產者在 taskQueue 中添加一個元素,并稱為`notifyAll()`方法。 由于上次`wait()`方法是由使用者線程調用的(這就是生產者處于等待狀態的原因),因此使用者可以獲取通知。 * 收到通知后的使用者線程,如果準備按照書面邏輯使用該元素。 * 請注意,兩個線程也都使用`sleep()`方法來模擬創建和使用元素時的時間延遲。 #### 2.2 使用者線程 以下是根據我們的要求使用的消費者線程的代碼: ```java class Consumer implements Runnable { private final List<Integer> taskQueue; public Consumer(List<Integer> sharedQueue) { this.taskQueue = sharedQueue; } @Override public void run() { while (true) { try { consume(); } catch (InterruptedException ex) { ex.printStackTrace(); } } } private void consume() throws InterruptedException { synchronized (taskQueue) { while (taskQueue.isEmpty()) { System.out.println("Queue is empty " + Thread.currentThread().getName() + " is waiting , size: " + taskQueue.size()); taskQueue.wait(); } Thread.sleep(1000); int i = (Integer) taskQueue.remove(0); System.out.println("Consumed: " + i); taskQueue.notifyAll(); } } } ``` * 此處,`consume()`代碼已在無限循環內編寫,以便使用者在`taskQueue`中發現某些內容時便繼續使用元素。 * 一旦`wait()`完成,使用者將刪除 taskQueue 中的一個元素,并調用`notifyAll()`方法。 由于生產者線程調用了上次的`wait()`方法(這就是為什么生產者處于等待狀態的原因),所以生產者會收到通知。 * 獲取通知后的生產者線程(如果準備按照書面邏輯生產元素)。 #### 2.3 測試生產者消費者示例 現在讓測試生產者和使用者線程。 ```java public class ProducerConsumerExampleWithWaitAndNotify { public static void main(String[] args) { List<Integer> taskQueue = new ArrayList<Integer>(); int MAX_CAPACITY = 5; Thread tProducer = new Thread(new Producer(taskQueue, MAX_CAPACITY), "Producer"); Thread tConsumer = new Thread(new Consumer(taskQueue), "Consumer"); tProducer.start(); tConsumer.start(); } } ``` 程序輸出。 ```java Produced: 0 Consumed: 0 Queue is empty Consumer is waiting , size: 0 Produced: 1 Produced: 2 Consumed: 1 Consumed: 2 Queue is empty Consumer is waiting , size: 0 Produced: 3 Produced: 4 Consumed: 3 Produced: 5 Consumed: 4 Produced: 6 Consumed: 5 Consumed: 6 Queue is empty Consumer is waiting , size: 0 Produced: 7 Consumed: 7 Queue is empty Consumer is waiting , size: 0 ``` 我建議您將生產者線程和使用者線程花費的時間更改為不同的時間,并檢查不同情況下的不同輸出。 ## 3\. 關于`wait()`,`notify()`和`notifyAll()`方法的面試問題 #### 3.1 調用`notify()`并且沒有線程正在等待時會發生什么? 通常,如果正確使用這些方法,則在大多數情況下并非如此。 盡管如果在沒有其他線程等待時調用`notify()`方法,則`notify()`只會返回而通知將丟失。 由于*等待和通知機制*不知道它正在發送通知的條件,因此,假設沒有線程正在等待,通知就不會被聽到。 稍后執行`wait()`方法的線程必須等待另一個通知發生。 #### 3.2 在`wait()`方法釋放或重新獲取鎖的時間段內是否存在競爭條件? `wait()`方法與鎖定機制緊密集成。 在等待線程已經可以接收通知的狀態之前,實際上不會釋放對象鎖。 這意味著僅當線程狀態更改為能夠接收通知時,才會保留鎖定。 該系統可防止在此機制中發生任何競賽情況。 同樣,系統確保在將線程移出等待狀態之前,對象應完全持有鎖定。 #### 3.3 如果線程收到通知,是否可以保證條件設置正確? 簡單地說,不。 在調用`wait()`方法之前,線程應始終在保持同步鎖的同時測試條件。 從`wait()`方法返回后,線程應始終重新測試條件以確定是否應該再次等待。 這是因為另一個線程也可以測試條件并確定不需要等待 - 處理通知線程設置的有效數據。 當通知中涉及多個線程時,這是一種常見情況。 更具體地說,正在將處理數據的線程視為使用者。 它們使用其他線程產生的數據。 無法保證當消費者收到通知時,該通知尚未被其他消費者處理。 這樣,當消費者醒來時,它無法假定其等待的狀態仍然有效。 它可能在過去是有效的,但是在調用`notify()`方法之后以及使用者線程喚醒之前,狀態可能已經更改。 等待線程必須提供檢查狀態的選項,并在通知已被處理的情況下返回到等待狀態。 這就是為什么我們總是在循環中放置對`wait()`方法的調用的原因。 #### 3.4 當多個線程正在等待通知時會發生什么? 調用`notify()`方法時,哪個線程實際獲得通知? 這取決于許多因素。Java 規范沒有定義要通知哪個線程。 在運行時中,哪個線程實際接收到通知取決于幾個因素,包括 Java 虛擬機的實現以及程序執行期間的調度和計時問題。 即使在單個處理器平臺上,也無法確定多個線程中的哪個接收通知。 就像`notify()`方法一樣,`notifyAll()`方法不允許我們決定哪個線程獲取通知:它們都被通知了。 當所有線程都收到通知時,可以設計出一種機制,讓線程在它們之間選擇哪個線程應該繼續,哪個線程應該再次調用`wait()`方法。 #### 3.5 `notifyAll()`方法是否真的喚醒所有線程? 是的,沒有。 所有等待的線程都被喚醒,但是它們仍然必須重新獲取對象鎖。 因此,線程不會并行運行:它們必須各自等待對象鎖被釋放。 因此,一次只能運行一個線程,并且只能在調用`notifyAll()`方法的線程釋放其鎖之后運行。 #### 3.6 如果根本只執行一個線程,為什么要喚醒所有線程? 有幾個原因。 例如,可能有多個條件要等待。 由于我們無法控制哪個線程獲取通知,因此通知完全有可能喚醒正在等待完全不同條件的線程。 通過喚醒所有線程,我們可以設計程序,以便線程在它們之間決定下一步應執行哪個線程。 另一種選擇是生產者生成的數據可以滿足多個消費者的需求。 由于可能難以確定有多少消費者可以對該通知感到滿意,因此可以選擇全部通知他們,從而允許消費者在他們之間進行分類。 學習愉快!
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看