生产者和消费者问题学习以及Java实现
在计算机领域中,生产者-消费者问题(也叫bounded-buffer问题)是一类很经典的多进程同步问题。该问题描述了两类进程,即生产者进程和消费者进程,它们共享一个固定大小的缓冲区作为队列。生产者的任务是产生数据,并放到缓冲区中;同时消费者会消费数据(或者说将数据从缓冲区中移走)。每次生产或者消费数据的个数都是一个。在解决该问题时要确保当缓冲区满了之后,不会再向其中添加数据;当缓冲区为空的时候,消费者不能从中提取数据。
当缓冲区满了时,生产者要么进入休眠状态,要么丢弃产生的数据。等到下次消费者从缓冲区中移走一项数据之后,要通知生产者继续往缓冲区中添加数据。同样的,当消费者发现缓冲区为空时,消费者进入休眠状态。当生产者往缓冲区中写入数据之后,生产者要唤醒消费者来消费数据。该问题可以通过进程间通信来解决,典型的做法是使用信号量。如果该问题解决不当会导致死锁,即生产者和消费者都处于等待唤醒的状态。
这里参考了网上的写法,写了一个很简单的版本。有4个文件:
1. 容器,Container.java
2. 生产者,Producer.java
3. 消费者,Consumer.java
4. 测试文件,Test.java
Producer.java
package com.tuhooo.practice.pcmodel; /**
* 生产者
*/
public class Producer implements Runnable { private Container<Integer> container;
private Object producerMonitor;
private Object consumerMonitor; Producer(Container<Integer> container, Object producerMonitor, Object consumerMonitor) {
this.container = container;
this.producerMonitor = producerMonitor;/*生产者的锁*/
this.consumerMonitor = consumerMonitor;/*消费者的锁*/
} public void run() {
while (true) {
produce();
}
} private void produce() { if (container.isFull()) {
synchronized (producerMonitor) {
try {
if (container.isFull()) {
producerMonitor.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
synchronized (producerMonitor) {
if (!container.isFull()) {
container.add(0);
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("生产者【" + Thread.currentThread().getId() + "】生产了一个, 一共" + container.getSize() + "个");
}
}
} if (!container.isEmpty()) {
synchronized (consumerMonitor) {
if (!container.isEmpty()) {
consumerMonitor.notify();
}
}
}
}
}
Consumer.java
package com.tuhooo.practice.pcmodel; /**
* 消费者
*/
public class Consumer implements Runnable { private Container<Integer> container;
private Object producerMonitor;
private Object consumerMonitor; Consumer(Container<Integer> container, Object producerMonitor, Object consumerMonitor) {
this.container = container;
this.producerMonitor = producerMonitor;/*生产者的锁*/
this.consumerMonitor = consumerMonitor;/*消费者的锁*/
} public void run() {
while (true) {
consume();
}
} /*消费方法怎么写*/
private void consume() { if (container.isEmpty()) {
//消费者挂起
synchronized (consumerMonitor) {
try {
if (container.isEmpty()) {
consumerMonitor.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
synchronized (consumerMonitor) {
if (!container.isEmpty()) {
container.get();
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("消费者【" + Thread.currentThread().getId() + "】消费了一个, 还有" + container.getSize() + "个");
}
}
} if (!container.isFull()) {
synchronized (producerMonitor) {
if (!container.isFull()) {
producerMonitor.notify();
}
}
}
}
}
Container.java
package com.tuhooo.practice.pcmodel; import java.util.LinkedList;
import java.util.List; /**
* 容器
*/
public class Container<T> { private int capacity;
private List<T> list; public Container(int capacity) {
this.capacity = capacity;
list = new LinkedList<T>();
} /*往容器中添加*/
public synchronized boolean add(T product) {
if(list.size() < capacity) {
list.add(product);
return true;
}
return false;
} /*从容器中取*/
public synchronized T get() {
if(list.size() > 0) {
list.remove(0);
}
return null;
} /*判断是否是满的*/
public boolean isFull() {
return list.size() >= capacity;
} public boolean isEmpty() {
return list.size() == 0;
} public synchronized int getSize() {
return list.size();
} public int getCapacity() {
return this.capacity;
}
}
Container有点坑的地方就是不知道什么时候应该加synchronized
Test.java
package com.tuhooo.practice.pcmodel; public class Test { public static void main(String[] args) { Container<Integer> container = new Container<Integer>(10);
Object producerMonitor = new Object();
Object consumerMonitor = new Object(); Thread p1 = new Thread(new Producer(container, producerMonitor, consumerMonitor));
Thread p2 = new Thread(new Producer(container, producerMonitor, consumerMonitor));
Thread c1 = new Thread(new Consumer(container, producerMonitor, consumerMonitor));
Thread c2 = new Thread(new Consumer(container, producerMonitor, consumerMonitor)); p1.start();
p2.start();
c1.start();
c2.start();
}
}
目前先就这么写,暂时运行起来没啥问题,如果有问题恳请各位看官指出。
有待改进地方:
- Container有没有更好的实现方法
- Container可以有多个,这样的话可以随机找到一个可用的Container分配给Producer或者Consumer用
- 感觉代码中有好多的synchronized,感觉性能不是很好
=========================== 更新 ==================
今天再来看这个其实是有问题的,不需要用到两把锁,是因为get和add都是同步方法,那么在执行任意一个的时候dou必须获取对象的锁,其实这两个方法同一时间只有一个可以运行,根本不需要用到两把锁,直接把Container当作锁就可以了。
生产者和消费者问题学习以及Java实现的更多相关文章
- “全栈2019”Java多线程第二十五章:生产者与消费者线程详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Android(java)学习笔记71:生产者和消费者之等待唤醒机制
1. 首先我们根据梳理我们之前Android(java)学习笔记70中关于生产者和消费者程序思路: 2. 下面我们就要重点介绍这个等待唤醒机制: (1)第一步:还是先通过代码体现出等待唤醒机制 pac ...
- Android(java)学习笔记11:生产者和消费者之等待唤醒机制
1. 首先我们根据梳理我们之前Android(java)学习笔记70中,关于生产者和消费者程序思路: 2. 下面我们就要重点介绍这个等待唤醒机制: (1)第一步:还是先通过代码体现出等待唤醒机制 下面 ...
- JAVA学习第二十七课(多线程(六))- 多生产者多消费者问题(JDK1.5新特性)
多生产者多消费者问题 以生产馒头 消费馒头为例. class Resource { private String name; private int count = 1; private boolea ...
- Java线程(学习整理)--4---一个简单的生产者、消费者模型
1.简单的小例子: 下面这个例子主要观察的是: 一个对象的wait()和notify()使用情况! 当一个对象调用了wait(),那么当前掌握该对象锁标记的线程,就会让出CPU的使用权,转而进入该对 ...
- java学习之生产者和消费者案例
package com.gh.thread; /** * 生产者和消费者案例 * wait和sleep的区别 * wait不让出监视器锁,sleep让出监视器的锁 * @author ganhang ...
- JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题
JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序猿杜鹏程的博客:http://blog ...
- java生产者与消费者模式
前言: 生产者和消费者模式是我们在学习多线程中很经典的一个模式,它主要分为生产者和消费者,分别是两个线程, 目录 一:生产者和消费者模式简介 二:生产者和消费者模式的实现 声明:本例来源于java经典 ...
- JAVA之旅(十五)——多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止
JAVA之旅(十五)--多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止 我们接着多线程讲 一.生产者和消费者 什么是生产者和消费者?我们 ...
随机推荐
- SSIS实践入门1:我的第一个SSIS程序开发
深圳,和你见面已经有23天的时间了,第10天敲定了我人生中的第三份工作,虽说不是和想象中的工作那么好,但是我感觉我已经提前进入了备战状态,接下来我希望自己在你的领土可以有所发展,深圳,一个人多的城市, ...
- nginx-rtmp流媒体服务器搭建【转】
nginx-rtmp https://github.com/pengqiuyuan/nginx-rtmp nginx-rtmp 流媒体服务器的搭建(采集桌面,手机直播) 在线Demo,直播自己的pc机 ...
- UVA 10652 Board Wrapping 计算几何
多边形凸包.. .. Board Wrapping Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu ...
- Unity3D 多人协作开发 环境搭建 笔记(场景合并)
http://www.cnblogs.com/zhaoqingqing/p/3371120.html 说到多人协作开发,大家都会想到要使用版本控制工具来管理项目,当然最常用的要数SVN和Git了,但是 ...
- 【Unity优化】怎样实现Unity编辑器中的协程
Unity编辑器中何时须要协程 当我们定制Unity编辑器的时候,往往须要启动额外的协程或者线程进行处理.比方当运行一些界面更新的时候,须要大量计算,假设用户在不断修正一个參数,比方从1变化到2.这种 ...
- 算法笔记_035:寻找最小的k个数(Java)
目录 1 问题描述 2 解决方案 2.1 全部排序法 2.2 部分排序法 2.3 用堆代替数组法 2.4线性选择算法 1 问题描述 有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低. 2 ...
- Linux 监测磁盘常用的工具sar iostat vmstat
Linux 检测内存常用的工具sar iostat vmstat #每秒刷新一次显示2次 sar -d 1 2 iostat -kx 1 2 vmstat -d 1 2 磁盘统计信息解释 tps 每秒 ...
- Tags Used In OpenERP 7.0
In OpenERP 7.0. the form view of each object has been redesigned so that the object the user is work ...
- Android studio中导入第三方类库
常常在github上看到一些好用的框架,但是对于一个新手怎样在android studio上导入去总会遇到各种麻烦,索性来研究下第三方类库怎样在android studio上导入. 以我在github ...
- ASP.NET总结
ASP.NET已经学习完.学牛腩的时候面对一些控件和方法会用,但对当中的原理还不懂.学习这部分的内容时, 从头到尾都有一种相识的感觉,把之前一些不懂得地方也理解了,每个知识都有相应的样例练习,学起来还 ...