深入多线程十五:管程方式解决生产者与消费者问题

在学习Java的道路上,是否路过多线程时总让你很迷惘;很不巧,我也是,而使我们感到很迷惘主要原因都源于没有对概念的深深的理解和实践。所以我决定漫步Java多线程,同你一起会会多线程。

深入多线程系列

深入多线程一:理解多线程在于深深地理解了多任务、进程、多线程、线程
深入多线程二:手撕多线程,从会三种创建多线程方式开始:除了常见的两种,你是否了解Callable接口方式?
深入多线程三:初遇并发问题:从一个小故事开始,从一行行代码开始
深入多线程四:停止多线程,你不会还以为是用stop和destroy吧?
深入多线程五:多线程为何要使用休眠?
深入多线程六:线程礼让与强制执行
深入多线程七:纯手绘图解多线程状态+代码示例,就问你怕了吗?
深入多线程八:多线程的优先级
深入多线程九:守护线程
深入多线程十:通过案例体会多线程的不安全
深入多线程十一: 超全synchronized的两种用法:同步方法与同步块
深入多线程十二:什么是死锁?
深入多线程十三:什么是Lock锁,比起synchronized锁有什么区别?
深入多线程十四:经典生产者与消费者问题,本质是线程通信问题
深入多线程十五:管程方式解决生产者与消费者问题
深入多线程十六:信号灯方式解决生产者与消费者问题
深入多线程十七:什么是池?线程池方式解决生产者与消费者问题

学习解决生产者与消费者问题之前,我觉得我还是有必要提醒一下;如果在没有理解生产者和消费者问题之前,务必要先看多线程系列十四,因为只有在对解决问题本身有深入的理解思考,才能有更好的解决。
深入多线程十四 经典生产者与消费者问题,本质是线程通信问题

什么是管程方式?

生产者 生产数据模块(可能是方法,对象,线程,进程)
消费者 处理数据的模块(可能是方法,对象,线程,进程)
缓冲区 生产者或消费者通过缓存区存取数据

可以简单滴理解成有两个人,他们在相隔很远的地方需要交谈(通信),那么他们只能通过电话或者微信等等方式,来实现交流。

也就说通过某个传输和接收信息的媒介,就能畅通的通信。

在这里插入图片描述

生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据。

手敲代码实现

创建生产者类

//生产者
class Producer implements Runnable{

    BufferContainer bufferContainer;

    public Producer(BufferContainer bufferContainer) {
        this.bufferContainer = bufferContainer;
    }

    //生产
    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            bufferContainer.push(new Cola(i));
            System.out.println("生产了第" + i + "瓶快乐水");
        }
    }
}

创建消费者类

//消费者
class Consumer implements Runnable{

    BufferContainer bufferContainer;

    public Consumer(BufferContainer bufferContainer) {
        this.bufferContainer = bufferContainer;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println("消费了" + bufferContainer.pop().c_id + "瓶快乐水");
        }
    }
}

创建产品类

/**
 * 产品
 * 一瓶快乐水
 */
class Cola{
    Integer c_id;
    public Cola(Integer c_id) {
        this.c_id = c_id;
    }
}

创建缓冲区类,是我们代码的核心

//缓冲区
class BufferContainer{
    //定义一个容器大小
    Cola[] colas = new Cola[5];
    //容器计数器
    int count = 0;

    //生产者投入产品
    public synchronized void push(Cola cola) {
        //如果容器满了,等待消费者来消费
        while(count == colas.length){
            //通知消费者消费,生产者等待
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
        //如果没有满,我们就需要投入产品
        colas[count] = cola;
        count++;

        //生产完毕,通知消费者消费
        this.notifyAll();
    }

    //消费者消费产品
    public synchronized Cola pop() {
        //判断消费者能否消费
        while(count == 0) {
             //等待生产者生产,消费者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //可以消费le
        count--;
        Cola cola = colas[count];
        //喝完了,通知生产者生产
        this.notifyAll();
        return cola;
    }
}

开启线程,让代码跑起来

public class ThreadDemo {

    public static void main(String[] args) {
        BufferContainer bufferContainer = new BufferContainer();
        new Thread(new Producer(bufferContainer)).start();
        new Thread(new Consumer(bufferContainer)).start();
    }
}

运行结果
在这里插入图片描述

最后:

也许有些小伙伴看了上面的代码很懵,但是这很正常;这里还是建议你能对多线程系列十四的生产者和产品者问题(本质是通信问题),能有深深理解;再回头看代码时,你也许会发出感叹:

啊,舒畅 !

最后的最后,为了更好的阅读体验,我把想说的话都放在了下面,嘿嘿。

我是一颗剽悍的种子 把我会的,认真的分享 是我写博客一直不变的信条。
如果你能看到这篇博文,说明咱们还是很有缘的;希望能带给你一些许帮助,创作的不易,
把我文章的知识带走,你的三连留下,点赞,评论,关注,是我最大的动力。

猜你喜欢

转载自blog.csdn.net/A_hxy/article/details/108275215