Java多线程(十):BlockingQueue实现生产者消费者模型
BlockingQueue
BlockingQueue、解决了多线程中,如何高效安全“传输”数据的问题。程序员无需关心什么时候阻塞线程,什么时候唤醒线程,该唤醒哪个线程。
方法介绍

BlockingQueue是Queue的子类
void put(E e)
插入指定元素,当BlockingQueue为满,则线程阻塞,进入Waiting状态,直到BlockingQueue有空闲空间再继续。
这里以ArrayBlockingQueue为例进行分析


void take()
队首出队,当BlockingQueue为空,则线程阻塞,进入Waiting状态,直到BlockingQueue不为空再继续。


int drainTo(Collection<? super E> c)
从队列中批量取出数据,并放入到另一个集合中,返回转移数据的数量,只需一次加锁和解锁。
BlockingQueue的实现类
ArrayBlockingQueue
/*
* Concurrency control uses the classic two-condition algorithm
* found in any textbook.
*/
/** Main lock guarding all access */
final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;
基于数组实现的BlockingQueue,需要指定队列容量,可以指定是否为公平锁;只有一个ReentrantLock,生产者和消费者不能异步执行。
LinkedBlockingQueue
/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();
基于链表实现的BlockingQueue,可以指定队列容量,不指定队列容量默认为Integer.MAX_VALUE;有两个ReentrantLock,生产者和消费者可以异步执行。
BlockingQueue实现生产者消费者模型
- 缓冲区可以存放大量数据
- 生产者和消费者速度各不相同
public class MyThread42 {
public static void main(String[] args)
{
final BlockingQueue<String> bq = new ArrayBlockingQueue<String>(10);
Runnable producerRunnable = new Runnable()
{
int i = 0;
public void run()
{
while (true)
{
try
{
System.out.println("我生产了一个" + i++);
bq.put(i + "");
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
};
Runnable customerRunnable = new Runnable()
{
public void run()
{
while (true)
{
try
{
System.out.println("我消费了一个" + bq.take());
Thread.sleep(3000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
};
Thread producerThread = new Thread(producerRunnable);
Thread customerThread = new Thread(customerRunnable);
producerThread.start();
customerThread.start();
}
}
输出结果如下
我生产了一个0
我消费了一个1
我生产了一个1
我生产了一个2
我消费了一个2
我生产了一个3
我生产了一个4
我生产了一个5
我消费了一个3
我生产了一个6
我生产了一个7
我生产了一个8
我消费了一个4
我生产了一个9
我生产了一个10
我生产了一个11
我消费了一个5
我生产了一个12
我生产了一个13
我生产了一个14
我消费了一个6
我生产了一个15
我生产了一个16
我消费了一个7
我生产了一个17
我消费了一个8
我生产了一个18
我消费了一个9
我生产了一个19
我消费了一个10
我生产了一个20
我消费了一个11
我生产了一个21
我消费了一个12
我生产了一个22
我消费了一个13
我生产了一个23
我消费了一个14
我生产了一个24
······
生产者没有生产到BlockingQueue的容量(极限是10)之前,生产3个,消费1个,再生产到BlockingQueue的容量之后,生产一个消费一个,因为不能超过BlockingQueue的容量。
Java多线程(十):BlockingQueue实现生产者消费者模型的更多相关文章
- Java多线程15:Queue、BlockingQueue以及利用BlockingQueue实现生产者/消费者模型
Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移 ...
- Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例
Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例 本文由 TonySpark 翻译自 Javarevisited.转载请参见文章末尾的要求. Java.util.concurr ...
- 多线程学习-基础(十二)生产者消费者模型:wait(),sleep(),notify()实现
一.多线程模型一:生产者消费者模型 (1)模型图:(从网上找的图,清晰明了) (2)生产者消费者模型原理说明: 这个模型核心是围绕着一个“仓库”的概念,生产者消费者都是围绕着:“仓库”来进行操作, ...
- java 多线程并发系列之 生产者消费者模式的两种实现
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度. 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据 ...
- Java 多线程学习笔记:生产者消费者问题
前言:最近在学习Java多线程,看到ImportNew网上有网友翻译的一篇文章<阻塞队列实现生产者消费者模式>.在文中,使用的是Java的concurrent包中的阻塞队列来实现.在看完后 ...
- 【Java并发编程】:生产者—消费者模型
生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 这里实现如下情况的生产--消费模型: 生产者不断交替地生产两组数据“姓 ...
- Java多线程之并发协作生产者消费者设计模式
两个线程一个生产者个一个消费者 需求情景 两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个 涉及问题 同步问题:如何保证同一资源被多个线程并发访问时的完整性.常用的同步方法是采用标 ...
- java多线程系列15 设计模式 生产者 - 消费者模式
生产者-消费者 生产者消费者模式是一个非常经典的多线程模式,比如我们用到的Mq就是其中一种具体实现 在该模式中 通常会有2类线程,消费者线程和生产者线程 生产者提交用户请求 消费者负责处理生产者提交的 ...
- Java多线程—阻塞队列和生产者-消费者模式
阻塞队列支持生产者-消费者这种设计模式.该模式将“找出需要完成的工作”与“执行工作”这两个过程分离开来,并把工作项放入一个“待完成“列表中以便在随后处理,而不是找出后立即处理.生产者-消费者模式能简化 ...
随机推荐
- 检测系统中进程占满单个cpu的情况
#!/bin/bash function thread_used_cpu(){ # $1 为单个cpu负载的百分比 if [[ $1 == "" ]];then full_load ...
- SOCKET原理(转载)
SOCKET原理 一.套接字(socket)概念 套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元.它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息: ...
- JVM-类加载子系统
类的生命周期 1.加载 将.class二进制字节流流从磁盘读到内存中(通过文件的全限定名读取) 2.连接 2.1验证:验证字节码文件的正确性 2.2准备:给类的静态变量分配内存,并赋予默认值(比如 i ...
- Delphi repeat Until 运用
procedure TForm3.SpeedButton1Click(Sender: TObject); Var I:integer; begin I:=; repeat I:=I+; ; ShowM ...
- MVVM的项目学习和笔记
今天在学习一个用MVVM模式写的项目,掌握一下对MVVM的理解和记的一些笔记. 下面是自己学习的项目链接: http://www.code4app.com/ios/一个MVVM架构的iOS工程/695 ...
- ubuntu 18.04设置开机自动挂载移动硬盘
首先在命令行执行df -h指令,可以看到如下结果: zifeiy@zifeiy-PC1:~$ df -h 文件系统 容量 已用 可用 已用% 挂载点 udev 964M 0 964M 0% /dev ...
- Chrome安装json格式化工具jsonView
1.下载jsonView 有条件的童鞋可以去谷歌商店下载安装https://chrome.google.com/webstore/detail/pmajcnnfhjcebiafkonednglookd ...
- selenium+python自动化框架
流程: 环境准备 eclipse :需安装pydev.testng插件 python :安装python完成后,需 pip下安装selenium:命令: pip install selenium 我现 ...
- Java工程师学习指南第5部分:Java网络编程与NIO
本文整理了微信公众号[Java技术江湖]发表和转载过的Java网络编程相关优质文章,想看到更多Java技术文章,就赶紧关注本公众号吧. 深度解读 Tomcat 中的 NIO 模型 [Java基本功]浅 ...
- shell脚本执行出现“期待整数表达式”
在执行shell时一直出现“integer expression expected”,找了很久也没发现那个地方出错.翻了笔记发现-le并不错啊,甚至还怀疑零是不是整数还特意上网搜了下 -_- . 最后 ...