博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java学习——生产者-消费者模式与线程通信问题(管程法、信号灯法)
阅读量:3941 次
发布时间:2019-05-24

本文共 4141 字,大约阅读时间需要 13 分钟。

Java学习——生产者消费者模式与线程通信问题(管程法)

什么是生产者消费者模式?

生产者消费者模式并不是23中设计模式中的一种,在面向对象编程中我们前人总结了一些比较好的设计模式,就像23种设计模式一样。但是面向过程编程的时候,我们前人也给我们总结了一些好的设计模式,比如今天我们要了解到的生产者-消费者模式。

在我们日常升生活中,常常会见到这样一种场景,比如我们取麦当劳买东西,当我们点完之后,会在一旁等待着我们的餐,然后做好了服务员就会通知我们取拿餐,这样一种简单的模式就是典型的生产者-消费者模式。

在我们多线程中要实现线程之间的通信(线程协作),就需要用到生产者-消费者模式

解决线程通信有两种方式:1.管程法 2.信号灯法

1.管程法

今天我们重点学习一下管程法,管程法主要以下几个要素:

  • 生产者:负责生产数据的模块(模块可以是方法、对象、线程、进程)
  • 消费者:负责处理数据的模块(模块可以是方法、对象、线程、进程)
  • 缓冲区:消费者不能直接使用生产者的数据,他们之间有“个缓冲区”; 生产者将生产好的数据放入缓冲区,消费者从缓冲区拿走数据

我们来看下代码实现:

/** * 线程通信-管程法 */public class ThreadPcOfTubeMethod {    public static void main(String[] args) {        SynchronizeContainer container = new SynchronizeContainer();        new Product(container).start();        new Consumers(container).start();    }}//1.生产者class Product extends Thread{    SynchronizeContainer container;    public Product(SynchronizeContainer container) {        this.container = container;    }    @Override    public void run() {        //生产        for (int i = 0; i < 100; i++) {            System.out.println("生产----->第"+i+"个面包");            container.push(new Bread(i));        }    }}//2.消费者class Consumers extends Thread{    SynchronizeContainer container;    public Consumers(SynchronizeContainer container) {        this.container = container;    }    @Override    public void run() {        //消费        for (int i = 0; i < 100; i++) {            System.out.println("消费----->第"+container.pop().id+"个面包");        }    }}//3.并发容器(缓冲区)://      1.存:容器不够了,不能存了,等待消费//      2.取:容器为空容器,等待生产class SynchronizeContainer{    Bread[] breads = new Bread[10];    int count = 0;//计数器        //生产----存储    public synchronized void  push(Bread bread){        //容器存在空间可以生产        //不能生产        if(count==breads.length){            try {                this.wait();//线程阻塞,消费者通知生产,阻塞解除            } catch (InterruptedException e) {                e.printStackTrace();            }        }        breads[count] = bread;        count++;        this.notifyAll();//存在数据了,通知消费    }    //消费----获取    public synchronized Bread pop(){        //如果容器中有数据,可以消费。        //如果没有数据,等待        if (count==0){            try {                this.wait();//线程阻塞,生产者通知消费解除阻塞            } catch (InterruptedException e) {                e.printStackTrace();            }        }        //从最后一个位置拿        count--;        Bread bread =breads[count];        this.notifyAll();//存在空间了,可以唤醒生产者生产了        return bread;    }}//4.商品(面包)class Bread{    int id;    public Bread(int id) {        this.id = id;    }}

2.信号灯法

我们简单的了解一下信号灯法,信号灯法是通过标志位来实现的。举一个演员表演,观众看的例子:

/** * 协作模型:生产者消费者实现方式二-信号灯法 * 思想:借助标志位 */public class ThreadPcOfSignalLight {    public static void main(String[] args) {        Tv tv = new Tv();        new Players(tv).start();        new Watchers(tv).start();    }}//生产者:演员class Players extends Thread{    Tv tv;    public Players(Tv tv){        this.tv=tv;    }    @Override    public void run() {        for (int i = 0; i < 20; i++) {            if (i%2==0){                this.tv.play("天龙八部");            }else {                this.tv.play("广告:天才第一步,雀氏纸尿裤");            }        }    }}//消费者:观众class Watchers extends Thread{    Tv tv;    public Watchers(Tv tv){        this.tv=tv;    }    @Override    public void run() {        for (int i = 0; i < 20; i++) {            tv.watch();        }    }}//同一个资源:电视class Tv{    String voice;    //信号灯,如果为真,表示观众等待    //信号灯,如果为假,表示演员等待    boolean flag = true;    //表演    public synchronized void play(String voice){        //演员等待        if (!flag){            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        System.out.println("演员表演了:"+voice);        this.voice=voice;        //唤醒        this.notifyAll();        //切换信号灯的状态        this.flag=!this.flag;    }    //观看    public synchronized void watch(){        //观众等待        if (flag){            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        System.out.println("观众听到了:"+voice);        //唤醒        this.notifyAll();        //切换信号灯的状态        this.flag=!this.flag;    }}

转载地址:http://baiwi.baihongyu.com/

你可能感兴趣的文章
ClickHouse集群搭建从0到1
查看>>
nginx实现请求的负载均衡 + keepalived实现nginx的高可用
查看>>
linux shell 中数组的定义和for循环遍历的方法
查看>>
求1!+2!+3!....+20!(java代码)
查看>>
VMware安装Ubuntu系统无法选择语言
查看>>
QT5.12安装
查看>>
Git/Github初步使用记录
查看>>
QT 开发问题合集
查看>>
Github使用问题合集
查看>>
QT多线程服务器
查看>>
Ubuntu 18.04.2 ulimit配置
查看>>
Ubuntu Mysql 安装与配置
查看>>
QT5.12 Mysql驱动未能加载问题
查看>>
现场直击|SequoiaDB@SIGMOD 2021:关注数据库的根科技存储技术
查看>>
赋能政企智慧办公,巨杉数据库与致远互联完成产品互认证
查看>>
SequoiaDB湖仓一体架构亮相 ACM SIGMOD 2021
查看>>
信通院发布第十二批大数据产品能力评测结果,巨杉数据库两款产品通过
查看>>
巨杉数据库荣获2020年度河南省科学技术进步奖
查看>>
湖仓一体提升管理效率 培育数据沃土
查看>>
报名启动!巨杉数据库 2021 湖仓一体技术大赛带你进入分布式技术的星辰大海
查看>>