JAVA多线程的等待与唤醒——生产者模型的理解

JAVA多线程的等待与唤醒——生产者模型的理解,第1张

JAVA多线程的等待与唤醒——生产者模型的理解

对于经典的生产者和消费者模型,我做出以下理解以及代码的测试:

1.线程的等待与唤醒适用于生产速度和消费速度不匹配的情况,这时候构造一个类似容器的东西,一方未完成的时候,另一方在此等待。等到另一方完成的时候将对方唤醒继续执行;好处是可以解耦生产者和消费者的关系,系统易于维护。

案例分析,想要得到的效果:
当前存在一个牛奶生产者和一个牛奶消费者,生产者把生产好的牛奶放入盒子中,消费者从盒子中取出。盒子最大能容纳5瓶牛奶,生产一瓶牛奶需要2秒钟,消费者消耗一瓶牛奶需要3秒钟。

这个时间是我自己考虑的设定,存在固定的时间差,能够更容易的看轻每一步的执行结果。

其次,消费者只需要5瓶牛奶。不设定上限的话,就是程序就是无限循环下去。

而生产者只要有需要就会一直生产;

//盒子的类

public class Box {
    private int milk;

    public Box(int milk) {
        this.milk = milk;
    }

    public Box() {
    }

    public synchronized int getMilk() {
        if(milk==0){
            try {
                System.out.println("没有牛奶,请等待");
                //执行到此处的线程就进行等待
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else {
            milk--;
            System.out.println("取走第"+(milk+1)+"瓶牛奶");
            //唤醒其他所有线程
            notifyAll();
        }
        return milk;
    }

    public synchronized void setMilk(int p) {
        if(milk==5){
            System.out.println("牛奶已满,请等待");
            try {
                //执行到此处的线程就进行等待
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else {
            milk++;
            System.out.println("放入第"+milk+"瓶牛奶");
            //唤醒其他所有线程
            notifyAll();
        }
    }
}
//顾客类

public class Custemer implements Runnable {
    private Box box;

    public Custemer(Box box) {
        this.box = box;
    }

    @Override
    public void run() {
        for (int i = 0; i < 6; i++) {
            box.getMilk();
            System.out.println("消费者循环执行次数" + (i + 1));
            try {
                //获取之后线程睡眠3秒
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
//生产者类

public class Producer implements Runnable {
    private Box box;

    public Producer(Box box) {
        this.box = box;
    }

    @Override
    public void run() {
        while (true){
            box.setMilk(1);
            System.out.println("正在生产牛奶,需2秒钟");
            try {
                //以线程睡眠代表生产时间
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
//主函数测试类

public class Test01 {

    public static void main(String[] args) {
        Box b = new Box();
        Producer p = new Producer(b);
        Custemer c = new Custemer(b);

        Thread tp = new Thread(p);
        Thread tc = new Thread(c);
        //启动线程
        tc.start();
        tp.start();

    }
}

1.执行结果的逐步分析如下图:

 总结:

wait()方法属于Object类,并不是任何一个线程属性,可以理解为一个标识,线程看到这个标识了就会自己进行等待。跟睡眠不同,睡眠是自己让自己睡眠,并且知道自己要睡多少,所以知道什么时候醒来。但是看到等待,却不知道自己要等多久,所以需要别人去唤醒他。

notify以及notifyall都可以唤醒线程。唤醒的时候并不能指定唤醒谁,要么随机唤醒一个,要么唤醒所有,建议多数情况下使用唤醒所有。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5677159.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存