Java多线程-----实现生产者消费者模式的几种方式
1 生产者消费者模式概述
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,
直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,
才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这种生产消费能力不均衡的问题,所以便有了生产者和消费者模式
2 实现生产者消费者模式
产品类
package com.thread.pc.blockingqueue; import java.util.UUID; /**
* 产品类
*
* @author yyx 2018年12月22日
*/
public class Product {
private UUID proCode; // 产品唯一编码 public Product(UUID proCode) {
super();
this.proCode = proCode;
} public UUID getProCode() {
return proCode;
} public void setProCode(UUID proCode) {
this.proCode = proCode;
} }
生产者
package com.thread.pc.lockcondition; /**
* 生产者
* @author yyx 2019年1月5日
*/
public class Producer implements Runnable {
private Warehouse warehouse; public Producer(Warehouse warehouse) {
super();
this.warehouse = warehouse;
} @Override
public void run() {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
warehouse.addProduct();
}
} }
消费者
package com.thread.pc.lockcondition; /**
* 消费者
*
* @author yyx 2019年1月5日
*/
public class Consumer implements Runnable {
private Warehouse warehouse; public Consumer(Warehouse warehouse) {
super();
this.warehouse = warehouse;
} @Override
public void run() {
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
warehouse.removeProduct();
}
}
}
2.1 使用lock、condition和await、singalAll
仓库类
package com.thread.pc.lockcondition; import java.util.List;
import java.util.UUID;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock; /**
* 仓库类
*
* @author yyx 2019年1月5日
*/
public class Warehouse {
private final int MAX_SIZE = 5;
private List<Product> listProduct;
private Lock lock;
private Condition conditionProducer;
private Condition conditionConsumer; public Warehouse(List<Product> listProduct, Lock lock, Condition conditionProducer, Condition conditionConsumer) {
super();
this.listProduct = listProduct;
this.lock = lock;
this.conditionProducer = conditionProducer;
this.conditionConsumer = conditionConsumer;
} public void addProduct() {
lock.lock();
try {
String currentName = Thread.currentThread().getName();
while (listProduct.size() >= MAX_SIZE) { // 为了避免虚假唤醒,应该总是使用在循环中
try {
System.out.println("产品列表已满,不再生产!" + currentName + "进入等待");
conditionProducer.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Product product = new Product(UUID.randomUUID());
System.out.println(currentName + "生产了一个产品,它的编号是:" + product.getProCode().toString());
listProduct.add(product);
conditionConsumer.signalAll();
} finally {
lock.unlock();
}
} public void removeProduct() {
lock.lock();
try {
String currentName = Thread.currentThread().getName();
while (listProduct.size() <= 0) {
try {
System.out.println("产品列表不足,不再消费!" + currentName + "进入等待");
conditionConsumer.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Product product = listProduct.get(0);
System.out.println(currentName + "消费了一个产品,它的编号是:" + product.getProCode().toString());
listProduct.remove(0);
conditionProducer.signalAll();
} finally {
lock.unlock();
}
}
}
测试类
package com.thread.pc.lockcondition; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 测试类
* @author 2018年12月22日
*/
public class TestModel {
public static void main(String[] args) {
List<Product> listProduct=new ArrayList<Product>();
Lock lock = new ReentrantLock();
Condition conditionProducer = lock.newCondition();
Condition conditionConsumer = lock.newCondition(); Warehouse warehouse = new Warehouse(listProduct,lock, conditionProducer,conditionConsumer);
Producer producer = new Producer(warehouse);
Consumer consumer = new Consumer(warehouse); new Thread(producer,"生产者A").start();
new Thread(producer,"生产者B").start();
new Thread(consumer,"消费者C").start();
new Thread(consumer,"消费者D").start();
}
}
2.2 使用synchronized修饰代码块
仓库类
package com.thread.pc.synchronizedcodeblock; import java.util.List;
import java.util.UUID; /**
* 仓库类
*
* @author yyx 2019年1月5日
*/
public class Warehouse {
private final int MAX_SIZE = 10; // 最大数量
private List<Product> listProduct; public Warehouse(List<Product> listProduct) {
super();
this.listProduct = listProduct;
} /**
* 生产产品
*/
public void addProduct() {
synchronized (listProduct) {
String currentName = Thread.currentThread().getName();
while (listProduct.size() >= MAX_SIZE) { // 为了避免虚假唤醒,应该总是使用在循环中
try {
System.out.println("产品列表已满,不再生产!" + currentName + "进入等待");
listProduct.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Product product = new Product(UUID.randomUUID());
System.out.println(currentName + "生产了一个产品,它的编号是:" + product.getProCode().toString());
listProduct.add(product);
listProduct.notifyAll();
}
} /**
* 消费产品
*/
public void removeProduct() {
synchronized (listProduct) {
String currentName = Thread.currentThread().getName();
while (listProduct.size() <= 0) {
try {
System.out.println("产品列表不足,不再消费!" + currentName + "进入等待");
listProduct.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Product product = listProduct.get(0);
System.out.println(currentName + "消费了一个产品,它的编号是:" + product.getProCode().toString());
listProduct.remove(0);
listProduct.notifyAll();
}
}
}
测试类
package com.thread.pc.synchronizedcodeblock; import java.util.ArrayList;
import java.util.List; /**
* 测试类
* @author yyx
* 2019年1月5日
*/
public class TestModel {
public static void main(String[] args) {
List<Product> listProduct = new ArrayList<Product>(); Warehouse warehouse = new Warehouse(listProduct);
Producer producer = new Producer(warehouse);
Consumer consumer = new Consumer(warehouse); new Thread(producer,"生产者A").start();
new Thread(producer,"生产者B").start();
new Thread(consumer,"消费者C").start();
new Thread(consumer,"消费者D").start();
}
}
2.3 使用synchronized修饰方法
仓库类
package com.thread.pc.synchronizedmethod; import java.util.List;
import java.util.UUID; /**
* 仓库类
*
* @author yyx 2019年1月5日
*/
public class Warehouse {
private final int MAX_SIZE = 10;
private List<Product> listProduct; public Warehouse(List<Product> listProduct) {
super();
this.listProduct = listProduct;
} /**
* 生产产品
*/
public synchronized void addProduct() {
String currentName = Thread.currentThread().getName();
while (listProduct.size() >= MAX_SIZE) {
try {
System.out.println("产品列表已满,不再生产!" + currentName + "进入等待");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Product product = new Product(UUID.randomUUID());
System.out.println(currentName + "生产了一个产品,它的编号是:" + product.getProCode().toString());
listProduct.add(product);
notifyAll();
} /**
* 消费产品
*/
public synchronized void removeProduct() {
String currentName = Thread.currentThread().getName();
while (listProduct.size() <= 0) {
try {
System.out.println("产品列表不足,不再消费!" + currentName + "进入等待");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Product product = listProduct.get(0);
System.out.println(currentName + "消费了一个产品,它的编号是:" + product.getProCode().toString());
listProduct.remove(0);
notifyAll();
}
}
测试类
package com.thread.pc.synchronizedmethod; import java.util.ArrayList;
import java.util.List; /**
* 测试类
*
* @author yyx 2019年1月5日
*/
public class TestModel {
public static void main(String[] args) {
List<Product> listProduct = new ArrayList<Product>(); Warehouse warehouse = new Warehouse(listProduct);
Producer producer = new Producer(warehouse);
Consumer consumer = new Consumer(warehouse); new Thread(producer, "生产者A").start();
new Thread(producer, "生产者B").start();
new Thread(consumer, "消费者C").start();
new Thread(consumer, "消费者D").start();
}
}
2.4 使用BlockingQueue
仓库类
package com.thread.pc.blockingqueue; import java.util.UUID;
import java.util.concurrent.BlockingQueue;
/**
* 仓库
* @author yyx 2018年12月22日
*/
public class Warehouse {
private final int MAX_SIZE = 10;
private BlockingQueue<Product> blockingQueue; public Warehouse(BlockingQueue<Product> blockingQueue) {
super();
this.blockingQueue = blockingQueue;
} public void addProduct() {
String currentName = Thread.currentThread().getName();
if (blockingQueue.size() >= MAX_SIZE) {
System.out.println("产品列表已满,不再生产!" + currentName + "进入等待");
} else {
Product product = new Product(UUID.randomUUID());
System.out.println(currentName + "生产了一个产品,它的编号是:" + product.getProCode().toString());
try {
blockingQueue.put(product);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public void removeProduct() {
String currentName = Thread.currentThread().getName();
if (blockingQueue.size() <= 0) {
System.out.println("产品列表不足,不再消费!" + currentName + "进入等待");
} else {
try {
Product product = blockingQueue.take();
System.out.println(currentName + "消费了一个产品,它的编号是:" + product.getProCode().toString());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试类
package com.thread.pc.blockingqueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* 测试类
* @author yyx 2018年12月22日
*/
public class TestModel {
public static void main(String[] args) {
BlockingQueue<Product> blockingQueue = new LinkedBlockingQueue<>(10); Warehouse warehouse = new Warehouse(blockingQueue);
Producer producer = new Producer(warehouse);
Consumer consumer = new Consumer(warehouse); new Thread(producer).start();
new Thread(producer).start();
new Thread(consumer).start();
}
}
Java多线程-----实现生产者消费者模式的几种方式的更多相关文章
- Java多线程_生产者消费者模式2
在我的上一条博客中,已经介绍到了多线程的经典案列——生产者消费者模式,但是在上篇中用的是传统的麻烦的非阻塞队列实现的.在这篇博客中我将介绍另一种方式就是:用阻塞队列完成生产者消费者模式,可以使用多种阻 ...
- 【多线程】java多线程实现生产者消费者模式
思考问题: 1.为什么用wait()+notify()实现生产者消费者模式? wait()方法可以暂停线程,并释放对象锁 notify()方法可以唤醒需要该对象锁的其他线程,并在执行完后续步骤,到了s ...
- JAVA多线程之生产者 消费者模式 妈妈做面包案例
创建四个类 1.面包类 锅里只可以放10个面包 ---装面包的容器2.厨房 kitchen 生产面包 和消费面包 最多生产100个面包3.生产者4消费者5.测试类 多线程经典案例 import ja ...
- Java多线程编程——生产者-消费者模式(1)
生产者-消费者模式在生活中非常常见.就拿我们去餐馆吃饭为例.我们会遇到以下两种情况: 1.厨师-客人 如下图所示,生产者.消费者直接进行交互. 生产者生产出产品后,通知消费者:消费者消费后,通知生产者 ...
- Java多线程_生产者消费者模式1
生产者消费者模型 具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品.生产消费者模式如下图.(图片来自网络 ...
- java多线程解决生产者消费者问题
import java.util.ArrayList; import java.util.List; /** * Created by ccc on 16-4-27. */ public class ...
- 【多线程】--生产者消费者模式--Lock版本
在JDK1.5发布后,提供了Synchronized的更优解决方案:Lock 和 Condition 我们使用这些新知识,来改进例子:[多线程]--生产者消费者模式--Synchronized版本 改 ...
- Java设计模式之生产者消费者模式
Java设计模式之生产者消费者模式 博客分类: 设计模式 设计模式Java多线程编程thread 转载 对于多线程程序来说,不管任何编程语言,生产者和消费者模型都是最经典的.就像学习每一门编程语言一 ...
- java多线程模拟生产者消费者问题,公司面试常常问的题。。。
package com.cn.test3; //java多线程模拟生产者消费者问题 //ProducerConsumer是主类,Producer生产者,Consumer消费者,Product产品 // ...
随机推荐
- LeetCode 977 Squares of a Sorted Array 解题报告
题目要求 Given an array of integers A sorted in non-decreasing order, return an array of the squares of ...
- nodejs prefix(全局)和cache(缓存)windows下设置
引:在安装完nodejs后,通过npm下载全局模块默认安装到{%USERDATA%}C:\Users\username\AppData\下的Roaming\npm下,这当然是不太对的默认. 1,安装L ...
- 使用Git,如何忽略不需要上传的文件(配置文件)
步骤1:在目录下,选择GIt Bash Here 2.输入命令 : git update-index --assume-unchanged 文件名 3.再输入指令 git status 查看修改文件 ...
- PHP三种运行方式(转载)
三种运行方式:mod_php5.cgi.fast-cgi 1. 通过HTTPServer内置的模块来实现, 例如Apache的mod_php5,类似的Apache内置的mod_perl可以对perl支 ...
- 第二节:Linux下检出项目和提交项目
1.在linux下获取项目: 2.在linux中提交项目: 这时候我们在光标处添加注释,然后保存退出. 再查看下状态: 接下来问题来了: 解决办法: vim .git/config 修改:[remot ...
- 微信公众号ID也可以修改了!
差不多一年前,微信团队宣布个人类帐号一个自然年内可主动修改两次名称,那一天大家奔走相告纷纷修改成自己早就心仪的名字,有人猛然发现公众号名字改了,可ID还是xiaopipi(小屁屁)这可如何是好,洗不去 ...
- 20180820 SQL 提示Error: String or binary data would be truncated
Error: String or binary data would be truncated,错误,是因为栏位给出的长度不够,增加初始化长度就可以了. 除了创建表的增加长度情况,还有一种是,SELE ...
- cxPivotGrid导出数据
导出数据,需要在uses区域引用cxExportPivotGridLink 根据导出类型使用以下过程 procedure cxExportPivotGridToHTML procedure cxExp ...
- Python--共享变量
- 共享变量: 当多个线程同时访问一个变量的时候,会产生共享变量的问题 - 案例11 - 解决变量:锁.信号灯 - 锁(Lock): - 是一个标志,表示一个线程在占用一些资源 - 使用方法 - 上锁 ...
- 前端框架之Vue(5)-条件渲染
v-if 在字符串模板中,比如 Django Template语法中,我们得像这样写一个条件块: <!-- Handlebars 模板 --> {%if 1%} <h1>Yes ...