Welcome everyone

wait & notify

java 汪明鑫 859浏览 2评论

wait & notify

 

之前学习过wait和notify,但是总是理不清楚,不太明白,今天整理一篇博客,

争取把wait和notify搞明白。

 

  • wait和notify是Object的方法,而不是Thread的方法。
  • Object的wait方法会导致当前线程陷入阻塞,直到其他线程调用了该Object的notify或者notifyAll方法才能将其唤醒,或者如果设置了阻塞时间,时间到了

自动唤醒。

  • wait、notify必须要在同步方法中使用,必须持有同步方法的monitor的所有权。
  • 当前线程执行了该对象的wait方法后,就会放弃该monitor的所有权并且进入与这个对象关联的wait set 中。在wait set可以等待被其他线程唤醒,重新持有monitor所有权。

 

 

写一个经典的生产者和消费者的例子:

/**
 * @author: wang ming xin
 * @create: 2019-01-12 13:00
 */

//生产饼干
public class MyBlockingQueue {

    private int max = 10;   //容量设置为10

    //静态内部类 饼干
    static class Cookie{

    }

    private LinkedList<Cookie> cookieQueue = new LinkedList<>();

    public void offer(Cookie cookie){
        synchronized (cookieQueue){
            if(cookieQueue.size() >= max){
                try {
                    System.out.println("装饼干的容器已经满了...");
                    cookieQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("做了一个新的饼干,热乎着呢...");
            cookieQueue.addLast(cookie);
            cookieQueue.notify();
        }
    }

    public Cookie take(){
        synchronized (cookieQueue){
            if(cookieQueue.size() == 0){
                try {
                    System.out.println("没饼干了,等待...");
                    cookieQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("买走一个饼干...");
            Cookie cookie = cookieQueue.removeFirst();
            cookieQueue.notify();

            return cookie;
        }
    }

}

 

写一个测试类:

/**
 * @author: wang ming xin
 * @create: 2019-01-12 13:12
 */
public class CookieCustomer {
    public static void main(String[] args){
      MyBlockingQueue queue = new MyBlockingQueue();

      new Thread(()->{
         while (true){

             try {
                 //模拟制作一个饼干消耗的时间
                 TimeUnit.SECONDS.sleep(1);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }

             queue.offer(new MyBlockingQueue.Cookie());
         }
      },"生产者").start();

      new Thread(()->{
          while(true){
              queue.take();

              try {
                  //模拟吃一个饼干消耗的时间
                  TimeUnit.SECONDS.sleep(10);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }

          }
      },"消费者").start();
    }
}

 

运行效果:

 

只要容器没满,生产者就一直制造饼干,并通知消费者可以购买

 

 

wait  VS sleep

wait和sleep也容器理解错误和使用错误,在这里顺便过一下

 

  • 都可以让线程进入阻塞状态。
  • wait是Object的方法,而sleep是Thread的方法。
  • wait方法的执行必须在同步方法中进行,而sleep不需要。
  • 在同步方法中执行sleep方法时,线程抱着monitor锁沉睡,而wait方法会直接放弃monitor的所有权。

 

另外还有一点就是可以不用Thread.sleep( ),

而用TimeUnit.SECONDS.sleep( ),比Thread.sleep( ) 功能更强大,编程更优雅

支持各种时间单位的slepp

 

java.util.concurrent.TimeUnit

 

notifyAll

最后了解下notifyAll

顾名思义和notify差不多,只是唤醒的是wait set中全部阻塞的线程,而notify只能唤醒wait set中的一个线程。

 

使用notifyAll改写阻塞队列,可以解决多线程(大于2个线程)通信数据不一致的问题,,

比如存在多个消费者或者多个生产者,

再使用notify就会出现问题

 

public class MyBlockingQueue1 {

    private int max = 10;   //容量设置为10

    //静态内部类 饼干
    static class Cookie{

    }

    private LinkedList<Cookie> cookieQueue = new LinkedList<>();

    public void offer(Cookie cookie){
        synchronized (cookieQueue){
            while (cookieQueue.size() >= max){
                try {
                    System.out.println("装饼干的容器已经满了...");
                    cookieQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("做了一个新的饼干,热乎着呢...");
            cookieQueue.addLast(cookie);
            cookieQueue.notifyAll();
        }
    }

    public Cookie take(){
        synchronized (cookieQueue){
            while (cookieQueue.size() == 0){
                try {
                    System.out.println("没饼干了,等待...");
                    cookieQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("买走一个饼干...");
            Cookie cookie = cookieQueue.removeFirst();
            cookieQueue.notifyAll();

            return cookie;
        }
    }

}

 

现在模拟2个消费者

public class CookieCustomer {
    public static void main(String[] args){
      MyBlockingQueue1 queue = new MyBlockingQueue1();

      new Thread(()->{
         while (true){

             try {
                 //模拟制作一个饼干消耗的时间
                 TimeUnit.SECONDS.sleep(1);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }

             queue.offer(new MyBlockingQueue1.Cookie());
         }
      },"生产者").start();

      new Thread(()->{
          while(true){
              queue.take();

              try {
                  //模拟吃一个饼干消耗的时间
                  TimeUnit.SECONDS.sleep(10);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }

          }
      },"消费者1").start();

        new Thread(()->{
            while(true){
                queue.take();

                try {
                    //模拟吃一个饼干消耗的时间
                    TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        },"消费者2").start();
    }
}

 

 

 

转载请注明:汪明鑫的个人博客 » wait & notify

喜欢 (0)

说点什么

2 评论 在 "wait & notify"

提醒
avatar
排序:   最新 | 最旧 | 得票最多
毛大大
游客

因为wait和notify是Object的方法,所以每个对象都有这两个方法。线程同步代码中调用wait方法,是会进入当前同步监视器对象的等待队列(阻塞),notify & notifyAll只会唤醒同一同步监视器对象中的等待队列中的线程。

wpDiscuz