Java learning-waiting and wake-up mechanism: producer and consumer issues

1. Inter-thread communication

It means that multiple threads are processing the same resource, but the processing actions (tasks of the threads) are different.

So why deal with inter-thread communication?
When multiple threads execute concurrently, the CPU will switch threads randomly by default. When we need multiple threads to [complete a task together], and we want them to have [regular execution], then the need for multiple threads Some coordinated communications to help us achieve multi-threaded co-operation of a piece of data.

How to ensure effective use of resources for inter-thread communication: When
multiple threads are processing the same resource and have different tasks, thread communication is needed to help solve the use or operation of the same variable between threads. That is, when multiple threads operate on the same piece of data, they avoid contention for the same shared variable. That is, we need to use certain means to enable each thread to effectively use resources. And this method is-waiting for the wake-up mechanism.

2. Wait for the wake-up mechanism

Refers to a coordination mechanism between multiple threads. Because there is not only competition between threads, like contention for locks, there will also be cooperation mechanisms between threads to cooperate to complete certain tasks.

That is, after a thread has performed a prescribed operation, it enters the waiting state (wait()), and waits for other threads to execute their designated code before waking it up (notify()); when there are multiple threads waiting, if If necessary, notifyAll() can be used to wake up all waiting threads.
wait/notify is a cooperation mechanism between threads.

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

【Note】 :

  1. The wait method and notify method must be called by the same lock object. Because: the corresponding lock object can wake up the thread after the wait method called by the same lock object through notify.
  2. The wait method and notify method are methods of the Object class. Because: the lock object can be any object, and the class of any object inherits the Object class.
  3. The wait method and notify method must be used in synchronous code blocks or synchronous functions. Because: these two methods must be called through the lock object.

Typical case: Producer and consumer problem (selling buns)

[Analysis]
Insert picture description here
[Program Demonstration]

    资源类:包子类
    设置包子的属性
    皮
    馅
    包子的状态;有true,没有false
public class BaoZi {
    
    
     String pi;
     String xian;
     //包子的状态;有true,没有false,设置初始值为false没有包子
    boolean flag = false;
}
生产者(包子铺)类:是一个线程类,可以继承Thread
设置线程任务(run):生产包子
对包子的状态进行判断
true:有包子
    包子铺调用wait方法进入等待状态
false:没有包子
    包子铺生产包子
    增加一些趣味性:交替生产两种包子
        有两种状态(%2==0)
    包子铺生产好了包子
    修改包子的状态为true有
    唤醒吃货线程,让吃货线程吃包子

注意:
    包子铺线程和吃货线程关系--->通信(互斥)
    必须采用同步技术保证两个线程只能有一个在执行
    锁对象必须保证唯一,可以使用包子对象作为锁对象
    包子铺类和吃货类就需要把包子对象作为参数传递进来
        1.需要在成员位置创建一个包子变量
        2.使用带参数的构造方法,为这个包子变量赋值
public class BaoZiPu extends Thread{
    
    

    //1.需要在成员位置创建一个包子变量
    private BaoZi bz;

    // 2.使用带参数的构造方法,为这个包子变量赋值

    public BaoZiPu(String name,BaoZi bz) {
    
    
        this.bz = bz;
    }

    //设置线程任务(run):生产包子
    @Override
    public void run() {
    
    
        //定义一个变量
        int count = 0;
        //让包子铺多生产几次包子
        while (true){
    
    
            //必须采用同步技术保证两个线程只能有一个在执行
            synchronized (bz) {
    
    
                //对包子的状态进行判断
                if (bz.flag == true) {
    
    
                    try {
    
    
                        bz.wait();
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }

                //没有包子,被唤醒之后执行,包子铺生产包子
                //增加一些趣味性:交替生产两种包子
                System.out.println("包子铺开始做包子");
                if (count % 2 ==0) {
    
    
                    //生产 “薄皮三鲜馅包子”
                    bz.pi = "薄皮";
                    bz.xian = "三鲜馅";
                }else {
    
    
                    //生产 “冰皮五仁馅包子”
                    bz.pi = "冰皮";
                    bz.xian = "五仁馅";
                }
                count++;
                System.out.println("包子铺正在生产:" + bz.pi + bz.xian +"包子");
                //生产包子需要3秒钟
                try {
    
    
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                //包子铺生产好了包子,修改包子的状态为true
                bz.flag = true;
                //唤醒吃货线程,让吃货线程吃包子
                bz.notify();
                System.out.println("包子铺做好了" + bz.pi+bz.xian+ "包子,吃货开吃了。");
            }
        }

    }
}
消费者(吃货)类:是一个线程类,可以继承Thread
设置线程任务(run):吃包子
对包子的状态进行判断
false;么有包子
    吃货调用wait方法进入等待状态
true:有包子
    吃货吃包子
    吃货吃完包子
    修改包子的状态为false没有
    吃货唤醒包子铺线程,生产包子
public class ChiHuo extends Thread{
    
    
    //1.需要在成员位置创建一个包子变量
    private BaoZi bz;

    // 2.使用带参数的构造方法,为这个包子变量赋值
    public ChiHuo(String name,BaoZi bz) {
    
    
        super(name);
        this.bz = bz;
    }
    //设置线程任务(run):吃包子
    @Override
    public void run() {
    
    
        // 对包子的状态进行判断
        while (true){
    
    
            synchronized (bz){
    
    
                if (bz.flag == false){
    
    
                    try {
    
    
                        bz.wait();
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
                //被唤醒之后执行的代码,吃包子
                System.out.println("吃货正在吃" +bz.pi+bz.xian+"包子");
                //吃货吃完包子,修改包子的状态为false没有
                bz.flag = false;
                //吃货唤醒包子铺线程,生产包子
                bz.notify();
                System.out.println("吃货已经把"+bz.pi+bz.xian+"包子吃完了,包子铺开始生产包子");
                System.out.println("=============================================");
            }
        }

    }
}
测试类:
包含main方法,程序执行的入口,启动程序
创建包子对象;
创建包子铺线程,开启,生产包子;
创建吃货线程,开启,吃包子
public class Demo {
    
    
    //包含main方法,程序执行的入口,启动程序
    public static void main(String[] args) {
    
    
        //创建包子对象;
        BaoZi bz = new BaoZi();
        //创建包子铺线程,开启,生产包子;
        new BaoZiPu("包子铺",bz).start();
        //创建吃货线程,开启,吃包子
        new ChiHuo("吃货",bz).start();

    }
}

【Operation Results】 :
Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_44664432/article/details/106813265