首页 > 技术文章 > 多线程-4.wait() notify() notifyAll() 生产者消费者模型

ningbing 2021-03-12 15:07 原文

1.wait()方法
  该方法继承于Object类。在调用obj.wait()方法后,当前线程会失去obj的锁。待其他线程调用obj.notify()或notifyAll()方法后进入锁等待池,争抢到锁后进行执行wait()后续代码。
  wait(long time)方法超时自动结束阻塞,进入锁等待池,争抢到锁后进行执行wait()后续代码。
jdk文档描述:
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.
2.notify()方法
  jdk文档描述
  Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.
  The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways:
  • By executing a synchronized instance method of that object.
  • By executing the body of a synchronized statement that synchronizes on the object.
  • For objects of type Class, by executing a synchronized static method of that class.
Only one thread at a time can own an object's monitor.

 源码:
/**
 * @throws  IllegalMonitorStateException  if the current thread is not
 *               the owner of this object's monitor.
 * @see        java.lang.Object#notifyAll()
 * @see        java.lang.Object#wait()
 */
public final native void notify();
3.notifyAll()方法
jdk文档描述
  Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling one of the wait methods.
 
  The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object. The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object.
 
  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.
源码
* @throws  IllegalMonitorStateException  if the current thread is not
 *               the owner of this object's monitor.
 * @see        java.lang.Object#notify()
 * @see        java.lang.Object#wait()
 */
public final native void notifyAll();
 
4.生产者消费者模型
  生产者不停生产,消费者不停消费。存储产品数量为[0,maxSize]。每次生产或消费时都要获取产品的监视器,当产品数量不符合要求不能生产或消费时,当前操作线程放出监视器,进入阻塞状态,同时唤醒所有在阻塞状态的生产者和消费者。存在一个runnable队列和一个blocked队列,runnale队列中存储的线程等待cpu调度随时可以运行,blocked只有调用obj.notify或notifyall方法后才能进入runnable队列。
代码如下:
 1 public class TestSetAndGet {
 2     static class Goods {
 3         public String lock = Thread.currentThread().getName()+"test";
 4         volatile static int number = 1;
 5         private static final int max_size = 10;
 6         
 7         // 生产者增加一个产品
 8         public void set() throws InterruptedException {
 9             synchronized (this) {
10                 while (number >= max_size) {
11                     // wait()方法一定要持有锁对象的minitor监视器,所以一定要放在notify之前
12                     wait();
13                 }
14                 if (number == 0) {
15                     System.out.print("-同时唤醒所有的消费者和生产者。");
16                     notifyAll();
17                 }
18                 number++;
19                 System.out.print("生产者增加一个,当前数量:"+number);
20                 System.out.println();
21             }
22         }
23         // 消费者消费一个产品
24         public void get() throws InterruptedException {
25             synchronized (this) {
26                 while (number <= 0) {
27                     // wait()方法一定要持有锁对象的minitor监视器,所以一定要放在notify之前
28                     wait();
29                 }
30                 if (number == max_size) {
31                     System.out.print("唤醒所有的消费者和生产者。");
32                     notifyAll();
33                 }
34                 number--;
35                 System.out.print("消费者消费一个,当前数量:"+number);
36                 System.out.println();
37             }
38         }
39     }
40 
41     public static void main(String[] args) throws InterruptedException {
42         Goods goods = new Goods();
43 
44         for (int i = 0; i < 20; i++) {
45             // 生产者慢一点,可以让货物在0-1之间盘桓
46             //Thread.sleep(100);
47             new Thread(()->{
48                 try {
49                     goods.set();
50                 } catch (InterruptedException e) {
51                     e.printStackTrace();
52                 }
53             }).start();
54         }
55         for (int i = 0; i < 20; i++) {
56             new Thread(()->{
57                 try {
58                     goods.get();
59                 } catch (InterruptedException e) {
60                     e.printStackTrace();
61                 }
62             }).start();
63         }
64 
65     }
66 }

 

推荐阅读