从头认识java-17.5 堵塞队列(以生产者消费者模式为例)
这一章节我们来讨论一下堵塞队列。我们以下将通过生产者消费者模式来介绍堵塞队列。
1.什么是堵塞队列?(摘自于并发编程网对http://tutorials.jenkov.com/java-concurrency/blocking-queues.html的翻译)
当队列是空的时。从队列中获取元素的操作将会被堵塞,或者当队列是满时。往队列里加入元素的操作会被堵塞。
试图从空的堵塞队列中获取元素的线程将会被堵塞,直到其它的线程往空的队列插入新的元素。相同。试图往已满的堵塞队列中加入新元素的线程相同也会被堵塞,直到其它的线程使队列又一次变得空暇起来,如从队列中移除一个或者多个元素。或者全然清空队列,下图展示了怎样通过堵塞队列来合作:
2.特性
(1)先进先出
(2)线程同步
3.以下结合生产者消费者模式来介绍堵塞队列的使用情况
package com.ray.ch17;
import java.util.concurrent.LinkedBlockingQueue;
public class Test {
public static void main(String[] args) {
Basket basket = new Basket();
Thread thread1 = new Thread(new Chief(basket));
Thread thread2 = new Thread(new Customer(basket));
Thread thread3 = new Thread(new Customer(basket));
thread1.start();
thread2.start();
thread3.start();
}
}
class Cake {
private static int index = 0;
private final int id = index++;
public int getId() {
return id;
}
public Cake() {
System.out.println("生产了蛋糕,id:" + id);
}
}
class Chief implements Runnable {
private Basket basket = null;
public Chief(Basket basket) {
this.basket = basket;
}
public void makeCake() throws InterruptedException {
for (int i = 0; i < 20; i++) {
basket.put(new Cake());
System.out.println("如今框里面的蛋糕数量:" + basket.getQueueSize());
Thread.sleep(20);
}
}
@Override
public void run() {
try {
makeCake();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Customer implements Runnable {
private Basket basket = null;
public Customer(Basket basket) {
this.basket = basket;
}
public void buyCake() throws InterruptedException {
System.out.println("消费了蛋糕,id:" + basket.take().getId());
System.out.println("如今框里面的蛋糕数量:" + basket.getQueueSize());
}
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
buyCake();
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Basket {
private LinkedBlockingQueue<Cake> queue = new LinkedBlockingQueue<Cake>(10);
public void put(Cake cake) throws InterruptedException {
queue.put(cake);
}
public Cake take() throws InterruptedException {
Cake cake = queue.take();
return cake;
}
public int getQueueSize() {
return queue.size();
}
}
输出:
生产了蛋糕,id:0
消费了蛋糕,id:0
如今框里面的蛋糕数量:0
如今框里面的蛋糕数量:0
生产了蛋糕,id:1
如今框里面的蛋糕数量:1
消费了蛋糕,id:1
如今框里面的蛋糕数量:0
生产了蛋糕,id:2
如今框里面的蛋糕数量:1
生产了蛋糕,id:3
如今框里面的蛋糕数量:2
生产了蛋糕,id:4
如今框里面的蛋糕数量:3
消费了蛋糕,id:2
如今框里面的蛋糕数量:2
生产了蛋糕,id:5
如今框里面的蛋糕数量:3
消费了蛋糕,id:3
如今框里面的蛋糕数量:2
生产了蛋糕,id:6
如今框里面的蛋糕数量:3
生产了蛋糕,id:7
如今框里面的蛋糕数量:4
生产了蛋糕,id:8
如今框里面的蛋糕数量:5
生产了蛋糕,id:9
如今框里面的蛋糕数量:6
消费了蛋糕,id:4
如今框里面的蛋糕数量:5
消费了蛋糕,id:5
如今框里面的蛋糕数量:4
消费了蛋糕,id:6
如今框里面的蛋糕数量:3
消费了蛋糕,id:7
如今框里面的蛋糕数量:2
消费了蛋糕,id:8
如今框里面的蛋糕数量:1
消费了蛋糕,id:9
如今框里面的蛋糕数量:0
解释:
(1)因为是生产者消费者模式,因此上面必须有生产者、消费者、篮子和消费的物品(蛋糕)这四个类。另一个Test測试类
(2)在Cake类里面,我们使用static的index来记录每个Cake的id
(3)在Basket类里面我们除了put和take方法,还放入一个getSize的方法来得到篮子里面如今有多少个Cake
(4)生产者和消费者事实上仅仅有一个方法就是生产make或者buy,这里面须要注意的是两个地方,第一个是数量,因为我们上面使用的是堵塞队列。因此当生产的总数量大于消费的总数量,程序就会一直在wait,仅仅有等到下一个消费者来消费才会继续运行,反之,假设消费的数量大于生产的数量也会出现这样的情况;第二个是时间,我们须要依照实际的时间匹配关系来配对时间,假设生产大于消费,在出现生产一个消费一个,须要添加生产者,假设是消费大于生产。则依据实际需求来定。
以下的代码须要等待,就是因为消费的总数大于生产的总数而出现的问题:
package com.ray.ch17;
import java.util.concurrent.LinkedBlockingQueue;
public class Test {
public static void main(String[] args) {
Basket basket = new Basket();
Thread thread1 = new Thread(new Chief(basket));
Thread thread2 = new Thread(new Customer(basket));
Thread thread3 = new Thread(new Customer(basket));
thread1.start();
thread2.start();
thread3.start();
}
}
class Cake {
private static int index = 0;
private final int id = index++;
public int getId() {
return id;
}
public Cake() {
System.out.println("生产了蛋糕,id:" + id);
}
}
class Chief implements Runnable {
private Basket basket = null;
public Chief(Basket basket) {
this.basket = basket;
}
public void makeCake() throws InterruptedException {
for (int i = 0; i < 20; i++) {
basket.put(new Cake());
System.out.println("如今框里面的蛋糕数量:" + basket.getQueueSize());
Thread.sleep(200);
}
}
@Override
public void run() {
try {
makeCake();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Customer implements Runnable {
private Basket basket = null;
public Customer(Basket basket) {
this.basket = basket;
}
public void buyCake() throws InterruptedException {
System.out.println("消费了蛋糕,id:" + basket.take().getId());
System.out.println("如今框里面的蛋糕数量:" + basket.getQueueSize());
}
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
buyCake();
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Basket {
private LinkedBlockingQueue<Cake> queue = new LinkedBlockingQueue<Cake>(10);
public void put(Cake cake) throws InterruptedException {
queue.put(cake);
}
public Cake take() throws InterruptedException {
Cake cake = queue.take();
return cake;
}
public int getQueueSize() {
return queue.size();
}
}
总结:这一章节我们通过生产者消费者模式来介绍了堵塞队列的特性。
这一章节就到这里,谢谢。
-----------------------------------
从头认识java-17.5 堵塞队列(以生产者消费者模式为例)的更多相关文章
- java ReentrantLock结合条件队列 实现生产者-消费者模式 以及ReentratLock和Synchronized对比
package reentrantlock; import java.util.ArrayList; public class ProviderAndConsumerTest { static Pro ...
- Java并发(基础知识)—— 阻塞队列和生产者消费者模式
1.阻塞队列 Blocki ...
- Java Thread系列(十)生产者消费者模式
Java Thread系列(十)生产者消费者模式 生产者消费者问题(producer-consumer problem),是一个多线程同步问题的经典案例.该问题描述了两个共亨固定大小缓冲区的线程-即所 ...
- Java并发编程()阻塞队列和生产者-消费者模式
阻塞队列提供了可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put方法将阻塞直到有空间可用:如果队列为空,那么take方法将会阻塞直到有元素可用.队列可以 ...
- Java多线程—阻塞队列和生产者-消费者模式
阻塞队列支持生产者-消费者这种设计模式.该模式将“找出需要完成的工作”与“执行工作”这两个过程分离开来,并把工作项放入一个“待完成“列表中以便在随后处理,而不是找出后立即处理.生产者-消费者模式能简化 ...
- Java的设计模式(7)— 生产者-消费者模式
生产者-消费者模式是一个经典的多线程设计模式,它为多线程间的协作提供了良好的解决方案.这个模式中,通常有两类线程,即若干个生产者线程和若干个消费者线程.生产者线程负责提交用户请求,消费者线程则负责具体 ...
- Java 学习笔记 使用synchronized实现生产者消费者模式
说明 Object.wait()使当前的线程进入到等待状态(进入到等待队列) Object.notifyAll() 唤醒等待中的全部线程 Object.notify() 随机唤醒一个线程 代码 con ...
- python进阶:Python进程、线程、队列、生产者/消费者模式、协程
一.进程和线程的基本理解 1.进程 程序是由指令和数据组成的,编译为二进制格式后在硬盘存储,程序启动的过程是将二进制数据加载进内存,这个启动了的程序就称作进程(可简单理解为进行中的程序).例如打开一个 ...
- Java设计模式—生产者消费者模式(阻塞队列实现)
生产者消费者模式是并发.多线程编程中经典的设计模式,生产者和消费者通过分离的执行工作解耦,简化了开发模式,生产者和消费者可以以不同的速度生产和消费数据.这篇文章我们来看看什么是生产者消费者模式,这个问 ...
随机推荐
- DTU
DTU 编辑 DTU (Data Transfer unit),是专门用于将串口数据转换为IP数据或将IP数据转换为串口数据通过无线通信网络进行传送的无线终端设备.DTU广泛应用于气象.水文水利.地质 ...
- matlab坐标轴设置
1. axis([xmin xmax ymin ymax]) 设置当前图形的坐标范围,分别为x轴的最小.最大值,y轴的最小最大值 2. V=axis 返回包含当前坐标范围的一个行向量 3. axis ...
- LVS/NAT
平台:RedHat Enterprise Linux centos6.3 ipvsadm ipvs 1. NAT模型 NAT模型:地址转换类型,主要是做地址转换,类 ...
- rsync数据同步工具的配置
rsync数据同步工具的配置 1. rsync介绍 1.1.什么是rsync rsync是一款开源的快速的,多功能的,可实现全量及增量的本地或远程数据同步备份的优秀工具.Rsync软件适用于 unix ...
- Linux学习之二-Linux系统的目录结构
Linux学习之二-Linux系统的目录结构 在Linux的根目录下,有很多的目录,但是需要记住,对于Linux而言,一切皆文件.因此此处的目录也是文件.用ls / 命令就能看到根目录下的各类不同的目 ...
- 转:windows 查找pid并kill进程
找出占用1099端口的进程,进入windows命令,查看什么进程占用了1099端口 使用命令:netstat -aon|findstr 1099 找出占用1099端口的进程,如下图所示:
- 在UC浏览器打开链接唤醒app,假设没有安装该app,则跳转到appstore下载该应用
在UC浏览器打开链接唤醒app,假设没有安装该app,则跳转到appstore下载该应用 须要在project中设置例如以下: 1.打开project中的myapp-Info.plist文件 2.打开 ...
- STL学习笔记(序列式容器)
Vector Vector是一个动态数组. 1.Vector的操作函数 构造.拷贝和析构 vector<Elem> c //产生一个空vector ,其中没有任何元素 vector< ...
- 【BIEE】09_BIEE控制台乱码问题解决
BIEE安装完成后,点击[启动BI服务] 接着从弹出窗口可以发现,全部汉字都是乱码 出现这种情况,想看一下BIEE启动情况是很费劲的,接着我们处理一下这个问题 1.从路径D:\obiee\user_p ...
- Web用户的身份验证及WebApi权限验证流程的设计和实现(续)
4.4 权限属性RequireAuthorizationAttribute [csharp] view plaincopy "font-size:14px;">/// / ...