`

(转)Java线程(篇外篇):阻塞队列BlockingQueue

 
阅读更多

  好久没有写文章了,这段时间事情比较杂,工作也比较杂乱,上周日刚搬完家,从自建房搬到了楼房,提升了一层生活品质,哈哈!不过昨天晚上在公交车上钱包被偷了,前段时间还丢个自行车,不得不感叹,京城扒手真多,还无人处理。言归正传,这一段时间我的工作主要是改进公司的调度器,调度器调度线程池执行任务,生产者生产任务,消费者消费任务,那么这时就需要一个任务队列,生产者向队列里插入任务,消费者从队列里提取任务执行,调度器里是通过BlockingQueue实现的队列,随后小查一下,下面看看BlockingQueue的原理及其方法。

       BlockingQueue最终会有四种状况,抛出异常、返回特殊值、阻塞、超时,下表总结了这些方法:

 

  抛出异常 特殊值 阻塞 超时
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
检查 element() peek() 不可用 不可用

 

 

       BlockingQueue是个接口,有如下实现类:

       1. ArrayBlockQueue:一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象必须明确大小,像数组一样。

       2. LinkedBlockQueue:一个可改变大小的阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象如果没有明确大小,默认值是Integer.MAX_VALUE。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。 

       3. PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序。

       4. SynchronousQueue:同步队列。同步队列没有任何容量,每个插入必须等待另一个线程移除,反之亦然。

       下面使用ArrayBlockQueue来实现之前实现过的生产者消/费者模式,代码如下:

 

[java] view plaincopy
 
  1. /** 定义一个盘子类,可以放鸡蛋和取鸡蛋 */  
  2. public class BigPlate {  
  3.   
  4.     /** 装鸡蛋的盘子,大小为5 */  
  5.     private BlockingQueue<Object> eggs = new ArrayBlockingQueue<Object>(5);  
  6.       
  7.     /** 放鸡蛋 */  
  8.     public void putEgg(Object egg) {  
  9.         try {  
  10.             eggs.put(egg);// 向盘子末尾放一个鸡蛋,如果盘子满了,当前线程阻塞  
  11.         } catch (InterruptedException e) {  
  12.             e.printStackTrace();  
  13.         }  
  14.   
  15.         // 下面输出有时不准确,因为与put操作不是一个原子操作  
  16.         System.out.println("放入鸡蛋");  
  17.     }  
  18.       
  19.     /** 取鸡蛋 */  
  20.     public Object getEgg() {  
  21.         Object egg = null;  
  22.         try {  
  23.             egg = eggs.take();// 从盘子开始取一个鸡蛋,如果盘子空了,当前线程阻塞  
  24.         } catch (InterruptedException e) {  
  25.             e.printStackTrace();  
  26.         }  
  27.   
  28.         // 下面输出有时不准确,因为与take操作不是一个原子操作  
  29.         System.out.println("拿到鸡蛋");  
  30.         return egg;  
  31.     }  
  32.       
  33.     /** 放鸡蛋线程 */  
  34.     static class AddThread extends Thread {  
  35.         private BigPlate plate;  
  36.         private Object egg = new Object();  
  37.   
  38.         public AddThread(BigPlate plate) {  
  39.             this.plate = plate;  
  40.         }  
  41.   
  42.         public void run() {  
  43.             plate.putEgg(egg);  
  44.         }  
  45.     }  
  46.   
  47.     /** 取鸡蛋线程 */  
  48.     static class GetThread extends Thread {  
  49.         private BigPlate plate;  
  50.   
  51.         public GetThread(BigPlate plate) {  
  52.             this.plate = plate;  
  53.         }  
  54.   
  55.         public void run() {  
  56.             plate.getEgg();  
  57.         }  
  58.     }  
  59.       
  60.     public static void main(String[] args) {  
  61.         BigPlate plate = new BigPlate();  
  62.         // 先启动10个放鸡蛋线程  
  63.         for(int i = 0; i < 10; i++) {  
  64.             new Thread(new AddThread(plate)).start();  
  65.         }  
  66.         // 再启动10个取鸡蛋线程  
  67.         for(int i = 0; i < 10; i++) {  
  68.             new Thread(new GetThread(plate)).start();  
  69.         }  
  70.     }  
  71. }  

       执行结果:

 

 

[plain] view plaincopy
 
  1. 放入鸡蛋  
  2. 放入鸡蛋  
  3. 放入鸡蛋  
  4. 放入鸡蛋  
  5. 放入鸡蛋  
  6. 拿到鸡蛋  
  7. 放入鸡蛋  
  8. 拿到鸡蛋  
  9. 拿到鸡蛋  
  10. 拿到鸡蛋  
  11. 放入鸡蛋  
  12. 放入鸡蛋  
  13. 放入鸡蛋  
  14. 拿到鸡蛋  
  15. 放入鸡蛋  
  16. 拿到鸡蛋  
  17. 拿到鸡蛋  
  18. 拿到鸡蛋  
  19. 拿到鸡蛋  
  20. 拿到鸡蛋  

       从结果看,启动10个放鸡蛋线程和10个取鸡蛋线程,前5个放入鸡蛋的线程成功执行,到第6个,发现盘子满了,阻塞住,这时切换到取鸡蛋线程执行,成功实现了生产者/消费者模式。java.util.concurrent包是个强大的包!

 

        本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/8108292

分享到:
评论

相关推荐

    深入理解Java线程编程中的阻塞队列容器

    阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景...

    BlockingQueue(阻塞队列)详解

    在新增的Concurrent包中,BlockingQueue...通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利。本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景。

    10、阻塞队列BlockingQueue实战及其原理分析.pdf

    6.JUC并发工具类在大厂的应用场景详解 (1).pdf 7、深入理解 AQS 独占锁之 Reentrantlock 源码分析 (1).pdf 8、读写锁ReentrantReadWriteLock&StampLock详解.pdf ...10、阻塞队列BlockingQueue 实战及其原理分析.pdf

    【Java】Queue、BlockingQueue和队列实现生产者消费者模式

    BlockingQueue接口 – 阻塞队列2.1 ArrayBlockingQueue类(有界阻塞队列)2.2 LinkedBlockingQueue类(无界阻塞队列)3. 源码:BlockingQueue实现生产者消费者模式→ 输出结果截图 1. Queue接口 – 队列 public ...

    阻塞队列BlockingQueue的使用

    在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题。通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利。本文简要介绍下BlockingQueue...

    个人总结的深入java多线程开发

    9)线程阻塞的条件(重要) 14 10) Interrupt()注意事项 16 三. 线程之间协作 17 1)演示简单的消费者和生产者的例子: 17 2)管道的读写流处理方式 19 3)重要的演示死锁的问题—哲学家就餐问题 20 4)终止多线程程序的两种...

    Java可阻塞队列-ArrayBlockingQueue

     ArrayBlockingQueue是由数组支持的有界阻塞队列,次队列按照FIFO(先进先出)原则,当队列已经填满,在去增加则会导致阻塞,这种阻塞类似线程阻塞。  ArrayBlockingQueue提供的增加和取出方法总结  使用...

    Java多线程 BlockingQueue实现生产者消费者模型详解

    主要介绍了Java多线程 BlockingQueue实现生产者消费者模型详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    线程安全队列Queue

    在项目启动时,开一个单线程来专门处理巡检任务的下发给巡检服务组件。使用BlockingQueue阻塞算法。BlockingQueue作为线程容器,可以为线程同步提供有力的保障。

    RustBlockingQueue:线程安全队列,在空时阻止出队

    RustBlockingQueue是使用线程安全的阻塞队列在线程之间进行通信的工具。 请注意,Rust消息传递工具执行的操作大致相同。 这很好地说明了如何构建线程之间可以共享的数据结构。 设计: 在此设计中,有一个结构...

    Java 常见并发容器总结

    可以看做一个线程安全的 `LinkedList`,这是一个非阻塞队列。 - **`BlockingQueue`** : 这是一个接口,JDK 内部通过链表、数组等方式实现了这个接口。表示阻塞队列,非常适合用于作为数据共享的通道。 - **`...

    Java容器.xmind

    阻塞队列 BlockingQueue接口 void put(E e) 将指定元素插入此队列,如果没有可用空间,则等待 E take()获取并移除此队列头部元素,如果没有可用元素,则等待 ArrayBlockingQueue 数组结构实现,有界队列,手工固定...

    Java并发编程实战

    5.3 阻塞队列和生产者-消费者模式 5.3.1 示例:桌面搜索 5.3.2 串行线程封闭 5.3.3 双端队列与工作密取 5.4 阻塞方法与中断方法 5.5 同步工具类 5.5.1 闭锁 5.5.2 FutureTask 5.5.3 信号量 5.5.4 栅栏 5.6...

    Java NIO+多线程实现聊天室

    阻塞队列BlockingQueue,生产者消费者模式 选择器 渠道 字节缓冲区 ProtoStuff 高性能序列化 HttpClient连接池 Spring依赖注入 lombok简化POJO开发 原子指标 内置锁 竣工服务 log4j+slf4j日志 实现的功能 登录注销 ...

    Java 并发编程实战

    5.3 阻塞队列和生产者-消费者模式 5.3.1 示例:桌面搜索 5.3.2 串行线程封闭 5.3.3 双端队列与工作密取 5.4 阻塞方法与中断方法 5.5 同步工具类 5.5.1 闭锁 5.5.2 FutureTask 5.5.3 信号量 5.5.4 栅栏 5.6...

    Java开发基于多线程和NIO实现聊天室源码+项目说明(含服务端+客户端).zip

    - 阻塞队列BlockingQueue,生产者消费者模式 - Selector - Channel - ByteBuffer - ProtoStuff 高性能序列化 - HttpClient连接池 - Spring依赖注入 - lombok简化POJO开发 - 原子变量 - 内置锁 - ...

    java线程池概念.txt

    //如果线程池线程大小大于核心线且且添加任务到线程失败,就把任务添加到阻塞队列 if (poolSize &gt;= corePoolSize || !addIfUnderCorePoolSize(command)) {//新建线程并启动 if (runState == RUNNING && workQueue...

    Java并发编程(学习笔记).xmind

    如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务 threadFactory 创建线程的工厂 handler 拒绝策略 unit 是一个枚举,表示 ...

    blocking-queue:COEN 283 的阻塞队列项目

    阻塞队列 COEN 283 的阻塞队列项目 通过阻塞队列传递消息 使用同步的消息缓冲区使用队列来实现阻塞队列,并在队列为空/满时进行自旋等待。 无锁消息缓冲区创建环形缓冲区; 在自旋等待期间使用 LockSupport,并使用...

Global site tag (gtag.js) - Google Analytics