参考资料: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. sequence(bzoj 1367)

    Description Input Output 一个整数R Sample Input 794820141518 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15 ...

  2. ubuntu 配置 samba, win7 map network device from linux

    一. samba的安装: # sudo apt-get insall samba # sudo apt-get install smbfs 二. 创建共享目录,或是找已经存在的文件夹,只要权限放开就行 ...

  3. linux 常见名词及命令(一)

    linux  PK  wondows 稳定且有效率.免费或少许费用.漏洞少且修补快.多任务多用户. 安全的用户及文件权限策略.适合小内核程序的嵌入系统.相对不耗资源. 热门的开源系统 红帽企业系统(R ...

  4. flex里InputText不能输入中文

    最近做项目都没做任何的更新,今天突然遇到在flex里的InputText无法进行中文输入,晚上查找了下资料,很多原因说是flashplayer的一个BUG. 在网上找到两种解决办法: 1.会出现这种情 ...

  5. rabbitmq management Login Failed

    默认用户guest 只允许localhost登录. so... 我们自己建立用户 1. 用户管理 用户管理包括增加用户,删除用户,查看用户列表,修改用户密码. 相应的命令 (1) 新增一个用户 rab ...

  6. 洛谷——P2820 局域网

    P2820 局域网 题目背景 某个局域网内有n(n<=100)台计算机,由于搭建局域网时工作人员的疏忽,现在局域网内的连接形成了回路,我们知道如果局域网形成回路那么数据将不停的在回路内传输,造成 ...

  7. 几道hash题

    1: UVa 10887 - Concatenation of Languages map 可以做 ,但是输入实在恶心,有空串之类的HASH模板: int Hash(char *s){   int s ...

  8. 转 gSOAP中使用TCP协议传输数据

    一  模型 TCP/IP是一个协议族(Internet protocol suite),包含众多的协议,传输控制协议(TCP)和网际协议(IP)分属不同的层次,是保证数据完整传输的两个基本的重要协议. ...

  9. [Tools] Create a Chrome Extension

    Creating a Chrome extension requires a manifest.json file which defines how your extension will beha ...

  10. 【转】TestNG执行顺序控制

    1.class执行顺序控制---testng.xml之preserve-order preserve-order:用来控制<test>里面所有<classes>的执行顺序.&l ...