文档章节

java并发编程的艺术笔记——wait、notify实现生产者消费者模式

会跳舞的机器人
 会跳舞的机器人
发布于 2017/08/26 14:52
字数 936
阅读 12
收藏 0

在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这种生产消费能力不均衡的问题,便有了生产者和消费者模式。

生产者和消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通信,而是通过阻塞队列来进行通信,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

容器队列

package main.java.com.robot.demo.productAndConsumer;

import java.util.LinkedList;

/**
 * @author: 会跳舞的机器人
 * @date: 2017/8/11 15:51
 * @description: 仓库
 */
public class Storage {
    /**
     * 仓库最大容量
     */
    private final int MAX_SIZE = 100;

    /**
     * 产品的存放队列
     */
    private LinkedList<Object> list = new LinkedList<>();

    /**
     * 生产产品
     */
    public void produce(int num) {
        synchronized (list) {
            while (list.size() + num > MAX_SIZE) {
                System.out.println("当前仓库产品数量为:" + list.size() + ",此次生产产品数量为:" + num + ",超过仓库最大容量:" + MAX_SIZE + ",不能再进行生产。");
                // 条件不满足,生产阻塞
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // 满足条件,生产num个产品
            for (int i = 0; i < num; ++i) {
                list.add(new Object());
            }
            System.out.println("此次生产产品数量为:" + num + ",仓库已用容量:" + list.size());
            // 通知
            list.notifyAll();
        }
    }

    /**
     * 消费产品
     */
    public void consume(int num) {
        synchronized (list) {
            while (list.size() < num) {
                System.out.println("此次消费产品数量为:" + num + ",产品库存为:" + list.size() + ",库存不足,暂时不能消费。");
                // 条件不满足,消费阻塞
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 满足条件,消费num个产品
            for (int i = 0; i < num; ++i) {
                list.remove();
            }
            System.out.println("此次消费产品数量为:" + num + ",产品库存为:" + list.size());
            // 通知
            list.notifyAll();
        }
    }
}

生产者

package main.java.com.robot.demo.productAndConsumer;

/**
 * @author: 会跳舞的机器人
 * @date: 2017/8/11 15:50
 * @description: 生产者
 */
public class Producer extends Thread {
    private int num;

    private Storage storage;

    public Producer(int num, Storage storage) {
        this.num = num;
        this.storage = storage;
    }

    @Override
    public void run() {
        storage.produce(num);
    }
}


消费者

package main.java.com.robot.demo.productAndConsumer;

/**
 * @author: 会跳舞的机器人
 * @date: 2017/8/11 15:50
 * @description: 消费者
 */
public class Consumer extends Thread {
    private int num;

    private Storage storage;

    public Consumer(int num, Storage storage) {
        this.num = num;
        this.storage = storage;
    }

    @Override
    public void run() {
        storage.consume(num);
    }
}

测试

package main.java.com.robot.demo.productAndConsumer;

/**
 * @author: 会跳舞的机器人
 * @date: 2017/8/11 16:29
 * @description:
 */
public class Test {
    public static void main(String[] args) {
        Storage storage = new Storage();

        Producer p1 = new Producer(10, storage);
        Producer p2 = new Producer(20, storage);
        Producer p3 = new Producer(50, storage);
        Producer p4 = new Producer(80, storage);

        Consumer c1 = new Consumer(30, storage);
        Consumer c2 = new Consumer(10, storage);
        Consumer c3 = new Consumer(60, storage);

        p1.start();
        p2.start();
        p3.start();
        p4.start();

        c1.start();
        c2.start();
        c3.start();
    }
}

测试结果输出:

此次生产产品数量为:10,仓库已用容量:10

此次生产产品数量为:50,仓库已用容量:60

当前仓库产品数量为:60,此次生产产品数量为:80,超过仓库最大容量:100,不能再进行生产。

此次消费产品数量为:30,产品库存为:30

此次生产产品数量为:20,仓库已用容量:50

此次消费产品数量为:10,产品库存为:40

当前仓库产品数量为:40,此次生产产品数量为:80,超过仓库最大容量:100,不能再进行生产。

此次消费产品数量为:60,产品库存为:40,库存不足,暂时不能消费。

© 著作权归作者所有

会跳舞的机器人
粉丝 6
博文 23
码字总数 28541
作品 0
广州
私信 提问
读书笔记之《Java并发编程的艺术》-并发编程基础

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
4K
8
Android--面试中遇到的问题总结(三)

《Android 开发工程师面试指南 LearningNotes 》,作者是陶程,由梁观全贡献部分。大家可以去知乎关注这两位用心的少年。这份指南包含了大部分Android开发的基础、进阶知识,不仅可以帮助准备...

sealin
2017/02/22
0
0
java基础thread——java5之后的多线程(浅尝辄止)

承上启下 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象L...

潇潇漓燃
2018/06/03
0
0
Java编程的逻辑 -- 并发章 -- 线程的基本协作机制

线程的基本协作 线程的基本协作示例 总结 线程的基本协作 多线程间除了竞争访问同一资源外,也经常需要相互协作的去执行一些任务。而对于协作的基本机制用的最多的无疑是wait/notify。 协作的...

HikariCP
2018/06/22
0
0
Java多线程学习(四)等待/通知(wait/notify)机制

系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Ja...

一只蜗牛呀
2018/04/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

java通过ServerSocket与Socket实现通信

首先说一下ServerSocket与Socket. 1.ServerSocket ServerSocket是用来监听客户端Socket连接的类,如果没有连接会一直处于等待状态. ServetSocket有三个构造方法: (1) ServerSocket(int port);...

Blueeeeeee
今天
6
0
用 Sphinx 搭建博客时,如何自定义插件?

之前有不少同学看过我的个人博客(http://python-online.cn),也根据我写的教程完成了自己个人站点的搭建。 点此:使用 Python 30分钟 教你快速搭建一个博客 为防有的同学不清楚 Sphinx ,这...

王炳明
昨天
5
0
黑客之道-40本书籍助你快速入门黑客技术免费下载

场景 黑客是一个中文词语,皆源自英文hacker,随着灰鸽子的出现,灰鸽子成为了很多假借黑客名义控制他人电脑的黑客技术,于是出现了“骇客”与"黑客"分家。2012年电影频道节目中心出品的电影...

badaoliumang
昨天
15
0
很遗憾,没有一篇文章能讲清楚线程的生命周期!

(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本。 简介 大家都知道线程是有生命周期,但是彤哥可以认真负责地告诉你网上几乎没有一篇文章讲得是完全正确的。 ...

彤哥读源码
昨天
15
0
jquery--DOM操作基础

本文转载于:专业的前端网站➭jquery--DOM操作基础 元素的访问 元素属性操作 获取:attr(name);$("#my").attr("src"); 设置:attr(name,value);$("#myImg").attr("src","images/1.jpg"); ......

前端老手
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部