Java(93):多线程之生产者和消费者模式(waitnotify通知机制)

Java(93):多线程之生产者和消费者模式(waitnotify通知机制),第1张

Java(93):多线程生产者消费者模式(wait/notify通知机制) 生产者消费者模式

        生产者和消费者模式:这其实是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件
对于生产者,没有生产产品之前,要通知消费者等待。而生产了产品之后,又需要马上通知消费者消费。
对于消费者,消费之后,要通知生产者已经消费完成,需要继续生产新的产品给消费者消费。
在生产者和消费者问题中,仅有synchronizede是不够的
synchronized可阻止并发更新同一个共享资源,实现了同步
synchronized不能用来实现不同线程之间的消息传递(通信)
线程通信:并发协助模型“生产者/消费者模式”->信号灯法。

         生产者消费者问题(Producer-consumer problem),也称为有限缓冲问题(Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享大小缓冲区的线程---既所谓的“生产者”和“消费者”----在实际运行时会发生的问题。生产者的主要作用时生成一定量的数据放到缓冲区中,然后重复此过程。以此同时,消费者也在缓冲区消费这些数据。该问题的关键是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消费数据。
       要解决这些问题,就必须让生产者在缓冲区满时休眠(要不干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。统一,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。如果解决办法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。

    Java提供了3个方法(java.lang.Object类的方法)解决线程之间的通信问题

方法名:这些方法只能放在同步里。
final void wait()  作用:表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁。
final void wait(long timeout)  作用:指定等待的毫秒数
final void notify()  作用:唤醒一个处于等待状态的线程
final void notifyAll()  作用:唤醒同一个对象上所有调用wait()方法的线程,优先级别搞得线程优先调度。

以下是:使用Object的wait/notify的消息通知机制
package runnable;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


class Tea{
    private String teaName;  //奶茶
    //信号灯
    //flag=T,生产者生产,消费者等待,生产完成后通知消费。
    //flag-F,消费者消费,生产者等待,消费完成后通知生产。
    boolean flag=true;  //信号灯

    public synchronized void Make(String teaName){
        if(!flag){  //生产者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //制作奶茶
        System.out.println(Thread.currentThread().getName()+",奶茶店制作了:"+teaName);
        this.teaName=teaName;   //制作完成
        //通知消费者
        this.notifyAll();
        //信号灯设置为false
        this.flag=false;
    }
    public synchronized void Take(){
        if(flag){  //消费者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //消费者消费
        System.out.println(Thread.currentThread().getName()+",消费者拿走了:"+teaName);
        //通知生产者
        this.notifyAll();
        //设置信号灯为true
        this.flag=true;
    }
}

//生产者
class Maker implements Runnable{
    public Tea tea;

    public Maker(Tea tea){
        this.tea=tea;
    }
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            if (i%2==0){
                this.tea.Make("珍珠奶茶");
            }else{
                this.tea.Make("香草奶茶");
            }
        }
    }
}

//消费者
class Taker implements Runnable{
    public Tea tea;

    public Taker(Tea tea){
        this.tea=tea;
    }
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            tea.Take();
        }
    }
}

       在使用线程的wait()等待/notify()通知机制时,一般都要配合一个 boolean 变量值(或者其他能够判断真假的条件),在 notify 之前改变该 boolean 变量的值,保证了程序的正确性。

2.1、new Thread()方式调用
//多线程执行
public class TeaTrading {
    public static void main(String[] args){

        //共同的资源
        Tea tea=new Tea();
        //生产者和消费者对象,使用同样的资源
        Maker marker=new Maker(tea);
        Taker taker=new Taker(tea);

        new Thread(marker).start();
        new Thread(taker).start();
  }
}

执行结果:

2.2、线程池方式调用
//多线程执行
public class TeaTrading {
    public static void main(String[] args){

        //共同的资源
        Tea tea=new Tea();
        //生产者和消费者对象,使用同样的资源

        //通过线程池执行
        int threadNum=5;
        ExecutorService service = Executors.newFixedThreadPool(threadNum);
        for(int i=0;i 

执行结果:

参考:一篇文章,让你彻底弄懂生产者--消费者问题 - 简书 (jianshu.com)

生产者消费者模式-Java实现 - 天目山电鳗 - 博客园 (cnblogs.com)

Java 多线程详解(四)------生产者和消费者 - YSOcean - 博客园 (cnblogs.com)

JAVA多线程之生产者消费者模型_L_R-CSDN博客_多线程生产者消费者

生产者、消费者问题(管程法与信号灯法) - 墨染念颖 - 博客园 (cnblogs.com)

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

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

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

发表评论

登录后才能评论

评论列表(0条)

保存