Java线程(篇外篇):阻塞队列BlockingQueue
2015-06-10 15:36
513 查看
改进公司的调度器,调度器调度线程池执行任务,生产者生产任务,消费者消费任务,那么这时就需要一个任务队列,生产者向队列里插入任务,消费者从队列里提取任务执行,调度器里是通过BlockingQueue实现的队列,随后小查一下,下面看看BlockingQueue的原理及其方法。
BlockingQueue最终会有四种状况,抛出异常、返回特殊值、阻塞、超时,下表总结了这些方法:
BlockingQueue是个接口,有如下实现类:
1. ArrayBlockQueue:一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象必须明确大小,像数组一样。
2. LinkedBlockQueue:一个可改变大小的阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象如果没有明确大小,默认值是Integer.MAX_VALUE。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
3. PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序。
4. SynchronousQueue:同步队列。同步队列没有任何容量,每个插入必须等待另一个线程移除,反之亦然。
下面使用ArrayBlockQueue来实现之前实现过的生产者消/费者模式,代码如下:
[java]
view plaincopyprint?
/** 定义一个盘子类,可以放鸡蛋和取鸡蛋 */
public class BigPlate {
/** 装鸡蛋的盘子,大小为5 */
private BlockingQueue<Object> eggs = new ArrayBlockingQueue<Object>(5);
/** 放鸡蛋 */
public void putEgg(Object egg) {
try {
eggs.put(egg);// 向盘子末尾放一个鸡蛋,如果盘子满了,当前线程阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
// 下面输出有时不准确,因为与put操作不是一个原子操作
System.out.println("放入鸡蛋");
}
/** 取鸡蛋 */
public Object getEgg() {
Object egg = null;
try {
egg = eggs.take();// 从盘子开始取一个鸡蛋,如果盘子空了,当前线程阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
// 下面输出有时不准确,因为与take操作不是一个原子操作
System.out.println("拿到鸡蛋");
return egg;
}
/** 放鸡蛋线程 */
static class AddThread extends Thread {
private BigPlate plate;
private Object egg = new Object();
public AddThread(BigPlate plate) {
this.plate = plate;
}
public void run() {
plate.putEgg(egg);
}
}
/** 取鸡蛋线程 */
static class GetThread extends Thread {
private BigPlate plate;
public GetThread(BigPlate plate) {
this.plate = plate;
}
public void run() {
plate.getEgg();
}
}
public static void main(String[] args) {
BigPlate plate = new BigPlate();
// 先启动10个放鸡蛋线程
for(int i = 0; i < 10; i++) {
new Thread(new AddThread(plate)).start();
}
// 再启动10个取鸡蛋线程
for(int i = 0; i < 10; i++) {
new Thread(new GetThread(plate)).start();
}
}
}
执行结果:
放入鸡蛋
放入鸡蛋
放入鸡蛋
放入鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
拿到鸡蛋
拿到鸡蛋
放入鸡蛋
放入鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
拿到鸡蛋
拿到鸡蛋
拿到鸡蛋
拿到鸡蛋
从结果看,启动10个放鸡蛋线程和10个取鸡蛋线程,前5个放入鸡蛋的线程成功执行,到第6个,发现盘子满了,阻塞住,这时切换到取鸡蛋线程执行,成功实现了生产者/消费者模式。java.util.concurrent包是个强大的包!
原文地址:/article/1391637.html。
BlockingQueue最终会有四种状况,抛出异常、返回特殊值、阻塞、超时,下表总结了这些方法:
抛出异常 | 特殊值 | 阻塞 | 超时 | |
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() | 不可用 | 不可用 |
1. ArrayBlockQueue:一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象必须明确大小,像数组一样。
2. LinkedBlockQueue:一个可改变大小的阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象如果没有明确大小,默认值是Integer.MAX_VALUE。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
3. PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序。
4. SynchronousQueue:同步队列。同步队列没有任何容量,每个插入必须等待另一个线程移除,反之亦然。
下面使用ArrayBlockQueue来实现之前实现过的生产者消/费者模式,代码如下:
[java]
view plaincopyprint?
/** 定义一个盘子类,可以放鸡蛋和取鸡蛋 */
public class BigPlate {
/** 装鸡蛋的盘子,大小为5 */
private BlockingQueue<Object> eggs = new ArrayBlockingQueue<Object>(5);
/** 放鸡蛋 */
public void putEgg(Object egg) {
try {
eggs.put(egg);// 向盘子末尾放一个鸡蛋,如果盘子满了,当前线程阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
// 下面输出有时不准确,因为与put操作不是一个原子操作
System.out.println("放入鸡蛋");
}
/** 取鸡蛋 */
public Object getEgg() {
Object egg = null;
try {
egg = eggs.take();// 从盘子开始取一个鸡蛋,如果盘子空了,当前线程阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
// 下面输出有时不准确,因为与take操作不是一个原子操作
System.out.println("拿到鸡蛋");
return egg;
}
/** 放鸡蛋线程 */
static class AddThread extends Thread {
private BigPlate plate;
private Object egg = new Object();
public AddThread(BigPlate plate) {
this.plate = plate;
}
public void run() {
plate.putEgg(egg);
}
}
/** 取鸡蛋线程 */
static class GetThread extends Thread {
private BigPlate plate;
public GetThread(BigPlate plate) {
this.plate = plate;
}
public void run() {
plate.getEgg();
}
}
public static void main(String[] args) {
BigPlate plate = new BigPlate();
// 先启动10个放鸡蛋线程
for(int i = 0; i < 10; i++) {
new Thread(new AddThread(plate)).start();
}
// 再启动10个取鸡蛋线程
for(int i = 0; i < 10; i++) {
new Thread(new GetThread(plate)).start();
}
}
}
执行结果:
放入鸡蛋
放入鸡蛋
放入鸡蛋
放入鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
拿到鸡蛋
拿到鸡蛋
放入鸡蛋
放入鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
拿到鸡蛋
拿到鸡蛋
拿到鸡蛋
拿到鸡蛋
从结果看,启动10个放鸡蛋线程和10个取鸡蛋线程,前5个放入鸡蛋的线程成功执行,到第6个,发现盘子满了,阻塞住,这时切换到取鸡蛋线程执行,成功实现了生产者/消费者模式。java.util.concurrent包是个强大的包!
原文地址:/article/1391637.html。
相关文章推荐
- Caused by: java.sql.SQLException: Incorrect integer value: '' for column 'clientId' at row 41
- Caused by: java.sql.SQLException: Incorrect integer value: '' for column 'clientId' at row 41
- MUI开发实战第二集---仿今日头条
- iis设置局域网访问,Context.Request.Url.Authority老是取出为localhost问题
- Android开发之ContentValues
- UIScrollView全部API学习。
- 生成19位数字GUID
- Visual Assist X 10.9.2063.0 build 2015.05.01 "准"正版破解补丁
- MUI开发实践教程第一集
- java中的clone()方法的研究---(6)如何编写正确的clone()方法:StringBuffer,StringBuilder
- 使用第三方的支持Block 的UIAlertView
- UISegementControl设置image不显示
- 学习笔记)蓝牙Bluetooth4.0 传统蓝牙与低功耗蓝牙
- the Suppress Reboot Issue
- 分享--> 书架UI实现
- 基于arduino UNO R3 的 MF RC522射频卡控制继电器的实验
- GRE写作issue和argument怎么写?
- 【转】Android UI 五种布局
- ProguardGui进行jar包代码混淆
- 【issue】支付宝SDK集成:openssl/asn1.h file not found