等待唤醒机制概述和等待唤醒机制需求分析和实现

什么是等待唤醒机制

这是多个线程间的一种协作机制。谈到线程我们经常想到了是线程间的竞争(race),比如去争夺锁,但是这并不是故事的全部,线程间也会有写作机制。就好比在公司里你和你们的同事门,你们可能存在晋升时的竞争,但更多时候你们呢更多是一起合作完成某些任务
就是在一个线程进行了规定操作后,就进入等待状态(wait),等待其他线程执行完他们指定的代码过后再将其唤醒(notity)在有多个线程进行等待的时候,如果需要可以使用notifyAll来唤醒所有等待的线程
wait/notify就是线程间的一种协作机制

等待唤醒中的方法:
等待唤醒即使就是用于解决线程间通信问题,使用到的3个方法的含义如下:
1.wait:线程不在活动,不再参与调度,进入wait set中,因此不会浪费cpu资源,也不会去竞争锁了,这时的线程状态即使WAIYING。它还要等着别的线程执行一个特别的动作,也就是通知(notify)在这个对象上等待的线程从wait set中释放出来,重新进入调度队列中
2.notify:则选取所统治对象的wait set中的一个线程释放;例如,参观有空位之后,等候就餐醉酒的顾客最先入座
3、notifyAll:则释放所通知对象的wait set上的全部线程
注意
哪怕只通知了一个等待的线程,被通知线程也不能立即回复执行,因此它当初中断的地方是在同步快内,而此刻它已经不持有锁,所以他需要再次尝试去获取锁成功后才能在当初调用wait方法之后的地方恢复执行

调用wait和notify方法需要注意的细节
1.wait方法与notify方法必须要由一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程
2.wait方法与notify方法是属于Object类方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的
3.wait方法与notify方法必须要在同步代码块或者同步函数中使用,因为必须要通过锁对象调用这两个方法
image

等待唤醒机制需求分析

生产者与消费者问题
等待唤醒机制其实就是经典的生产者和消费者的问题
就拿生产包子消费包子来说的呢个带唤醒机制如何有效利用资源
包子铺线程生产包子,吃货线程消费包子。当包子没有的时候包子的状态为false,吃货线程等待,包子铺线程生产包子
即包子状态为(true)并通知吃货线程解除吃货的等待状态,因为已经有包子了,那么包子铺线程进入等待状态。接下来
吃货线程能否进一步取决与锁的获取情况。如果吃货获取到锁,那么就执行吃包子的动作,包子吃饭包子的状态为false
并通知包子铺线程,词汇或线程进入等待状态,包子铺线程能否进一步执行则取决与锁的获取情况。

分析:需要哪些类
资源类:包子类
设置包子属性:皮,陷,包子的状态:有 true,没有false
生产者(包子铺)类:是一个线程类,可以继承Thread
设置线程任务(run):生产包子
对包子的状态进行判断
true:有包子 包子铺调用wait方法进入等待状态
false:没包子 包子铺生产包子 增加一些趣味性:交替生产两种包子
两种状态(i%2==0)
包子铺生产好了包子修改包子的状态为true
唤醒吃货线程,让吃货线程吃包子

消费者(吃货)类:是一个线程类可以继承Thread
设置线程任务(run):吃包子
对包子的状态进行判断:
true 有:吃货吃包子,吃完修改包子的状态
false 没有:吃货线程调用wait进入等待状态
唤醒包子铺线程生产包子

测试类(Test):包含main方法是程序启动的入口
创建包子对象:创建包子铺线程开启:创建吃货线程开启

代码实现:

package com.yang.Test.ThreadStudy;

import lombok.SneakyThrows;

public class MyTest {
    public static void main(String[] args) {
        BaoZi baoZi = new BaoZi();

        new BaoZiPu(baoZi).start();
        new ChiHuo(baoZi).start();
    }
}


class BaoZi {
    String pi;
    String xian;
    boolean flag = false;

}

class ChiHuo extends Thread {

    private BaoZi bz;

    public ChiHuo(BaoZi bz) {
        this.bz = bz;
    }

    @SneakyThrows
    @Override
    public void run() {
        while(true){
            synchronized (bz){
                if (bz.flag == false) {
                    bz.wait();
                }
                System.out.println("吃货吃"+bz.pi+bz.xian);
                bz.flag = false;
                bz.notify();
                System.out.println("吃货已经把"+bz.pi+bz.xian+"的包子吃饭了");
            }
        }
    }
}



class BaoZiPu extends Thread {
    private BaoZi bz;

    public BaoZiPu(BaoZi bz) {
        this.bz = bz;
    }
    @SneakyThrows
    @Override
    public void run() {
        int count = 0;
        while (true) {
            synchronized (bz) {
                if (bz.flag == true) {
                    bz.wait();
                }

                if (count % 2 == 0) {
                    bz.pi = "薄皮";
                    bz.xian = "三鲜馅";
                } else {
                    bz.pi = "冰皮";
                    bz.xian = "牛肉大葱馅";
                }
                count++;
                System.out.println("包子铺正在生产" + bz.pi + bz.xian + "包子");
                Thread.sleep(3000);

                bz.flag = true;
                bz.notify();
                System.out.println("包子铺已经生产好了" + bz.pi + bz.xian + "包子,吃货可以开始吃了");
            }
        }
    }
}

运行结果:
image

posted @ 2022-07-08 14:41  我滴妈老弟  阅读(52)  评论(0编辑  收藏  举报