参考资料:http://ifeve.com/java-synchronousqueue/
http://www.cnblogs.com/jackyuj/archive/2010/11/24/1886553.html
http://ifeve.com/java-blocking-queue/

BlockingQueue的几个API认识

方法 说明
boolean add(E e) 添加元素,返回true或者超出队列size上限后抛异常,若队列有大小限制时,官方更建议使用offer方法
boolean offer(E e) 添加元素,返回true或者false(超出队列size上限后)
void put(E e) throws InterruptedException 添加元素,无返回值,若空间不足则进入waiting状态直到有空间
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException 添加元素,返回true或者false(等待时间已到但仍无可添加空间),若空间不足则等待一定时间直到成功或者放弃
E take() throws InterruptedException 获取队列头部元素,若没有可取元素则进入waiting状态
E poll(long timeout, TimeUnit unit) throws InterruptedException 获取队列头部元素,若没有可取元素则等待一定时间直到成功或者放弃
boolean remove(Object o) 删除元素

BlockingQueue派生出几个常用的类ArrayBlockingQueue/LinkedBlockingDeque/DelayQueue/PriorityBlockingQueue/SynchronousQueue,类图如下所示:

它们的一些特性:

  • ArrayBlockingQueue:以数组保存元素,初始化时必须指定队列的容量capacity,添加元素时若达到上限进入阻塞
  • LinkedBlockingDeque:以双向链表保存元素,初始化时可指定队列的容量,若不指定,capacity默认为Integer.MAX_VALUE,添加元素时若达到上限进入阻塞
  • DelayQueue:以PriorityQueue保存元表,只能获取已到过期时间的元素,否则得到null,无容量上限,理论上可无限添加元素
  • PriorityBlockingQueue:以数组保存元素,整个队列为一棵平衡二叉树,添加元素成功后对队列内元素重排序,无容量上限,理论上可无限添加元素
  • SynchronousQueue:无缓存队列,生产者线程对其的插入操作put必须等待消费者的移除操作take,反过来也一样

ArrayBlockingQueue的使用案例可参考Java多线程系列三——实现线程同步的方法,本文测试DelayQueue的使用,代码如下:

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; /**
* @Description 利用DelayQueue清除超时请求<br/>
* 1. 主线程从工作队列取出任务处理完成后,把任务从超时队列移除<br/>
* 2. 超时检查线程找到超时请求后,把任务从工作队列中移除
*/
public class DelayQueueTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
int size = 36;
DelayQueue<MyRequest> queue = new DelayQueue<>();// 用于记录是否超时的队列
BlockingQueue<MyRequest> workQueue = new ArrayBlockingQueue<>(size);// 请求的队表
Map<Integer, MyRequest> cache = new HashMap<>();// 请求与id的对照表
for (int i = 0; i < size; i++) {// 初始化
MyRequest impl = new MyRequest(i, System.nanoTime(), 120);
queue.put(impl);
workQueue.put(impl);
cache.put(i, impl);
}
/**
* 建立超时检查任务
*/
Executors.newSingleThreadExecutor().submit(new Runnable() {
@Override
public void run() {
while (queue.size() > 0) {
try {
MyRequest impl = queue.take();
workQueue.remove(impl);// 若请求超时则把请求从队列中移除
System.out.println(String.format("%s is timeout", impl));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
/**
* 建2个线程消费请求
*/
ExecutorService executorService = Executors.newFixedThreadPool(2);
while (workQueue.size() > 0) {
List<MyRequest> tasks = Arrays.asList(new MyRequest[] { workQueue.take(), workQueue.take() });
List<Future<Integer>> futures = executorService.invokeAll(tasks);
for (Future<Integer> future : futures) {
queue.remove(cache.get(future.get()));// 若请求成功,则不需要再检查是否超时
}
}
executorService.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS);
executorService.shutdown();
}
} class MyRequest implements Delayed, Callable<Integer> {
private int threadId;
private long startTime;
private long expiredTime; public MyRequest(int threadId, long startTime, long timeout) {
this.threadId = threadId;
this.startTime = startTime;
this.expiredTime = TimeUnit.SECONDS.toNanos(timeout) + System.nanoTime();
} @Override
public Integer call() {
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("%s is ok", this));
return threadId;
} @Override
public int compareTo(Delayed arg0) {
int rtn;
if (arg0 == null || !(arg0 instanceof MyRequest)) {
rtn = 1;
} else {
MyRequest impl = (MyRequest) arg0;
rtn = startTime > impl.getStartTime() ? 1 : (startTime == impl.getStartTime() ? 0 : -1);
}
return rtn;
} @Override
public long getDelay(TimeUnit unit) {
return expiredTime - System.nanoTime();
} public long getStartTime() {
return startTime;
} @Override
public String toString() {
return String.format("MyRequest [threadId=%s, startTime=%s, expiredTime=%s]", threadId, startTime, expiredTime);
}
}

Java多线程系列十——BlockingQueue的更多相关文章

  1. Java多线程系列--“JUC集合”07之 ArrayBlockingQueue

    概要 本章对Java.util.concurrent包中的ArrayBlockingQueue类进行详细的介绍.内容包括:ArrayBlockingQueue介绍ArrayBlockingQueue原 ...

  2. Java多线程系列--“JUC集合”08之 LinkedBlockingQueue

    概要 本章介绍JUC包中的LinkedBlockingQueue.内容包括:LinkedBlockingQueue介绍LinkedBlockingQueue原理和数据结构LinkedBlockingQ ...

  3. Java多线程系列--“JUC集合”09之 LinkedBlockingDeque

    概要 本章介绍JUC包中的LinkedBlockingDeque.内容包括:LinkedBlockingDeque介绍LinkedBlockingDeque原理和数据结构LinkedBlockingD ...

  4. Java多线程系列--“JUC线程池”01之 线程池架构

    概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介绍JUC的最后一部分的内容——线程池.内容包括:线程池架构 ...

  5. Java多线程系列--“JUC线程池”02之 线程池原理(一)

    概要 在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析Th ...

  6. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  7. java多线程系列(六)---线程池原理及其使用

    线程池 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线程系列(三)之等待通知 ...

  8. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...

  9. Java多线程系列--“JUC锁”04之 公平锁(二)

    概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...

随机推荐

  1. vue验证码点击更新

    vue验证码点击更新 不说啥,直接贴代码 html: <img class="captcha" @click="editCaptcha" :src=&qu ...

  2. BZOJ2099: [Usaco2010 Dec]Letter 恐吓信

    给两个长度不超过50000的串,A串可每次截连续一段复制出来,求最少复制几次能得到B串. 方法一:SAM.不会. 嗯好会了. #include<stdio.h> #include<s ...

  3. Flex的Combobox组件使用技巧

    1.显示提示设置Prompt属性可以为Combobox添加一个默认提示.如果没有设置selectedIndex,默认selectedIndex=-1,就显示Prompt的内容.Flex3如果不设置Pr ...

  4. 如何判断一个app是原生app还是 webapp,或者是混合app

    1.(快速)滚动起来是否比较卡2.图片加载失败的图标 断网检查不是绝对的,web app并不一定是在远程服务器上的, 也能pack在程序里,load本地的资源也能算是web app.     web ...

  5. 洛谷——P2068 统计和

    P2068 统计和 题目描述 给定一个长度为n(n<=100000),初始值都为0的序列,x(x<=10000)次的修改某些位置上的数字,每次加上一个数,然后提出y (y<=1000 ...

  6. java代码编译过程

    简单随笔 java程序需要先编译成class文件然后才能执行,由于是编程成立机器代码,虚拟机加载内存的时候更快的执行. java文件编译成class文件步骤如下: 1)词法分析,检查每一个关键字单词是 ...

  7. 洛谷 P3879 [TJOI2010]阅读理解

    P3879 [TJOI2010]阅读理解 题目描述 英语老师留了N篇阅读理解作业,但是每篇英文短文都有很多生词需要查字典,为了节约时间,现在要做个统计,算一算某些生词都在哪几篇短文中出现过. 输入输出 ...

  8. Ubuntu 16.04安装双显卡驱动方法收集

    说明:不一定有效,要不断尝试. http://www.linuxwang.com/html/2150.html http://blog.csdn.net/feishicheng/article/det ...

  9. Meteor软件包管理

    Meteor 提供数千种开发应用程序,您可以使用社区包. 添加软件包 您可以查看Meteor官方包服务器: 点击这里. 只搜索你需要的包,并在命令提示符窗口中添加它. 例如,想使用 http 包添加到 ...

  10. [转]图解eclipse 查看原始类出现The jar file rt.jar has no source attachment

    原文:http://blog.csdn.net/u011514810/article/details/53196371 ---------------------------------------- ...