Java中wait()和notify()方法的使用


1. wait方法和notify方法

這兩個方法,包括notifyAll方法,都是Object類中的方法。在Java API中,wait方法的定義如下:

public final void wait()
                throws InterruptedException
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:

     synchronized (obj) {
         while (<condition does not hold>)
             obj.wait();
         ... // Perform action appropriate to condition
     }
 
This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.

在 Java 中可以用 wait、notify 和 notifyAll 來實現線程間的通信。線程在運行的時候,如果發現某些條件沒有被滿足,可以調用wait方法暫停自己的執行,並且放棄已經獲得的鎖,然后進入等待狀態。當該線程被其他線程喚醒並獲得鎖后,可以沿着之前暫停的地方繼續向后執行,而不是再次從同步代碼塊開始的地方開始執行。但是需要注意的一點是,對線程等待的條件的判斷要使用while而不是if來進行判斷。這樣在線程被喚醒后,會再次判斷條件是否正真滿足。

想象一下一個生產者,多個消費者的場景。一個消費者Consumer1了最后一個元素,並且喚醒了其他線程,如果被喚醒的正好是Consumer2,那么此時是沒有元素可以消費的。如果用的是if判斷,那么被喚醒后就不會再次進行條件的判斷,而是直接向下執行導致運行錯誤。我們的代碼如下:

notify方法會喚醒等待一個對象鎖的線程,但是具體喚醒哪個是不確定的。

 

2. 實現生產者消費者

如下使用if來判斷會導致程序出錯

一定要使用while來進行判斷線程的等待條件而不是使用if

  1 package thread.learn;
  2 
  3 import java.util.LinkedList;
  4 import java.util.Queue;
  5 import java.util.Random;
  6 
  7 /**
  8  * Created by liujinhong on 2017/4/2.
  9  * 生產者消費者問題是一個很經典的問題,值得好好研究一下
 10  * java的wait和notify方法在使用時也是要非常注意的
 11  */
 12 public class ProducerConsumer {
 13     public static class Producer extends Thread {
 14         Queue<Integer> queue;
 15         int maxsize;
 16 
 17         Producer(Queue<Integer> queue, int maxsize, String name) {
 18             this.queue = queue;
 19             this.maxsize = maxsize;
 20             this.setName(name);
 21         }
 22         @Override
 23         public void run() {
 24             while (true) {
 25                 synchronized (queue) {
 26                     try{
 27                         Thread.sleep(500);
 28                     } catch (Exception e) {}
 29 
 30                     System.out.println(this.getName() + "獲得隊列的鎖");
 31                     //條件的判斷一定要使用while而不是if
 32                     if (queue.size() == maxsize) {
 33                         System.out.println("隊列已滿,生產者" + this.getName() + "等待");
 34                         try {
 35                             queue.wait();
 36                         } catch (Exception e) {}
 37                     }
 38                     int num = (int)(Math.random()*100);
 39                     queue.offer(num);
 40 
 41                     System.out.println(this.getName() + "生產一個元素:" + num);
 42                     queue.notifyAll();
 43 
 44                     System.out.println(this.getName() + "退出一次生產過程!");
 45                 }
 46             }
 47         }
 48     }
 49 
 50     public static class Consumer extends Thread {
 51         Queue<Integer> queue;
 52         int maxsize;
 53 
 54         Consumer(Queue<Integer> queue, int maxsize, String name) {
 55             this.queue = queue;
 56             this.maxsize = maxsize;
 57             this.setName(name);
 58         }
 59 
 60         @Override
 61         public void run() {
 62             while (true) {
 63                 synchronized (queue) {
 64                     try{
 65                         Thread.sleep(500);
 66                     } catch (Exception e) {}
 67 
 68                     System.out.println(this.getName() + "獲得隊列的鎖");
 69                     //條件的判斷一定要使用while而不是if
 70                     if (queue.isEmpty()) {
 71                         System.out.println("隊列為空,消費者" + this.getName() + "等待");
 72                         try{
 73                             queue.wait();
 74                         } catch (Exception e) {}
 75                     }
 76                     int num = queue.poll();
 77                     System.out.println(this.getName() + "消費一個元素:"+num);
 78                     queue.notifyAll();
 79 
 80                     System.out.println(this.getName() + "退出一次消費過程!");
 81                 }
 82             }
 83         }
 84     }
 85 
 86     public static void main(String[] args) {
 87         Queue<Integer> queue = new LinkedList<>();
 88         int maxsize = 2;
 89 
 90         Producer producer = new Producer(queue, maxsize, "Producer");
 91         Consumer consumer1 = new Consumer(queue, maxsize,"Consumer1");
 92         Consumer consumer2 = new Consumer(queue, maxsize,"Consumer2");
 93         Consumer consumer3 = new Consumer(queue, maxsize,"Consumer3");
 94 
 95         producer.start();
 96         consumer1.start();
 97         consumer2.start();
 98         consumer3.start();
 99     }
100 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM