Java——等待唤醒机制(wait和notify)生产者消费者问题

1、什么是等待唤醒机制?

这是多个线程间的一种协作机制。谈到线程我们经常想到的是线程间的竞争(race),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制。就好比在公司里你和你的同事们,你们可能存在在晋升时的竞争,但更多时候你们更多是一起合作以完成某些任务。

就是在一个线程进行了规定操作后,就进入等待状态(wait()), 等待其他线程执行完他们的指定代码过后 再将其唤醒(notify());在有多个线程进行等待时, 如果需要,可以使用 notifyAll()来唤醒所有的等待线程。

wait/notify 就是线程间的一种协作机制。

1.1、等待唤醒中的方法

方法名 说明
public final void wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
public final void notify() 唤醒在此对象监视器上等待的单个线程。
public final void notifyAll() 唤醒在此对象监视器上等待的所有线程。

1.2、wait和notify方法的使用注意事项

1、wait方法与notify方法必须要由同一个锁对象调用因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。

2、wait方法与notify方法是属于Object类的方法的因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。

3、wait方法与notify方法必须要在同步代码块或者是同步函数中使用因为:必须要通过锁对象调用这2个方法。

2、生产者消费者问题

等待唤醒机制其实就是经典的“生产者与消费者”的问题。

2.1、案例说明 

这里定义一个生产者生产包子,消费者吃包子的案例,生产者线程生产包子,消费者线程消费包子。当包子没有时(包子状态为false),生产者线程等待,生产者线程生产包子(即包子状态为true),并通知消费者线程(解除消费者的等待状态),因为已经有包子了,那么生产者线程进入等待状态。接下来,消费者线程能否进一步执行则取决于锁的获取情况。如果消费者获取到锁,那么就执行吃包子动作,包子吃完(包子状态为false),并通知生产者线程(解除生产者的等待状态),消费者线程进入等待。生产者线程能否进一步执行则取决于锁的获取情况。

包子资源类

public class BaoZi {
    private String skin;//包子皮
    private String stuffing;//包子馅
    boolean flag=false;//包子资源是否存在 这里默认给定是没有


    public String getSkin() {
        return skin;
    }

    public void setSkin(String skin) {
        this.skin = skin;
    }

    public String getStuffing() {
        return stuffing;
    }

    public void setStuffing(String stuffing) {
        this.stuffing = stuffing;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
    
}

消费者类

public class Consumer extends Thread {
    private BaoZi bz;

    public Consumer(String name, BaoZi bz) {
        //super调用父类Thread的构造方法 赋值name
        super(name);
        this.bz = bz;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (bz) {
                //判断包子资源是否存在
                if (bz.flag == false) {
                    try {
                        bz.wait();//包子如果没有,则进入等待
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("消费者开始吃包子");
                //包子吃完后把资源设为false
                bz.setFlag(false);
                //唤醒生产者进行成产包子
                bz.notify();
            }
        }
    }
}

生产者类

public class Producer extends Thread{
    private BaoZi bz;
    private int count=0;

    public Producer(String name,BaoZi bz) {
        //super调用父类Thread的构造方法 赋值name
        super(name);
        this.bz = bz;
    }

    @Override
    public void run() {
        while (true){
            synchronized (bz){
                //判断包子资源是否存在
                if(bz.flag==true){
                    try {
                        bz.wait();//如果包子存在,则生产者进入等待
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //通过奇偶数来制作不同的包子,利于区分
                if(count%2==0){
                    bz.setSkin("白面皮");
                    bz.setStuffing("猪肉大葱馅");
                    System.out.println("生产者开始生产包子");
                    System.out.println("生产了"+bz.getSkin()+bz.getStuffing()+"包子");
                    count++;
                }else if(count%2==1){
                    bz.setSkin("荞麦面");
                    bz.setStuffing("胡萝卜粉条馅");
                    System.out.println("生产者开始生产包子");
                    System.out.println("生产了"+bz.getSkin()+bz.getStuffing()+"包子");
                    count++;
                }
                //把包子资源设为true
                bz.setFlag(true);
                //唤醒消费者去吃包子
                System.out.println("生产者可以来吃包子啦");
                bz.notify();

            }
        }
    }
}

测试类 

public class Test {
    public static void main(String[] args) {
        //定义一个包子对象,这个也是生产者和消费者共同的锁
        BaoZi bz=new BaoZi();
        //创建消费者和生产者对象,传递参数
        Consumer c=new Consumer("消费者",bz);
        Producer p=new Producer("生产者",bz);
        c.start();
        p.start();
    }
}

Java——等待唤醒机制(wait和notify)生产者消费者问题_第1张图片

因为默认给定包子的flag为false,所以在创建生产者对象时,检测到flag为false,所以生产者开始生产包子,而消费者进行等待,当生产者生产出包子后,进行等待,消费者被唤醒,开始吃包子。

你可能感兴趣的:(操作系统,java)