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

原文链接:http://blog.csdn.net/ghsau/article/details/8108292


好久没有写文章了,这段时间事情比较杂,工作也比较杂乱,上周日刚搬完家,从自建房搬到了楼房,提升了一层生活品质,哈哈!不过昨天晚上在公交车上钱包被偷了,前段时间还丢个自行车,不得不感叹,京城扒手真多,还无人处理。言归正传,这一段时间我的工作主要是改进公司的调度器,调度器调度线程池执行任务,生产者生产任务,消费者消费任务,那么这时就需要一个任务队列,生产者向队列里插入任务,消费者从队列里提取任务执行,调度器里是通过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 plain  copy
 print ?
  1. /** 定义一个盘子类,可以放鸡蛋和取鸡蛋 */  
  2. public class BigPlate {  
  3.   
  4.     /** 装鸡蛋的盘子,大小为5 */  
  5.     private BlockingQueue eggs = new ArrayBlockingQueue(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. }  
  72.        执行结果:

    [plain]  view plain  copy
     print ?
    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。

    12
    0
     
     

    我的同类文章

    Java SE(41)  Java 线程(14)
    • 再聊线程池2016-12-09阅读2205
    • Guava Predicate2016-06-18阅读1171
    • Java线程(十一):Fork/Join-Java并行计算框架2015-07-22阅读4592
    • Comparison method violates its general contract!2014-12-18阅读13155
    • Guava Collect2014-06-01阅读3835
    • Java序列化(二)2014-02-12阅读2617
    • Java奇淫巧技之Lombok2016-09-08阅读9335
    • 如何实现按距离排序、范围查找2016-01-30阅读7482
    • Collections.sort in JDK6:MergeSort2015-01-02阅读2591
    • Java线程(十):CAS2014-08-18阅读6614
    • Why hashcode 31?2014-03-16阅读2850
    更多文章

    参考知识库

    .NET知识库

    3178关注|827收录

    Java SE知识库

    22829关注|468收录

    Java EE知识库

    15277关注|1251收录

    Java 知识库

    23262关注|1441收录

    猜你在找
    ArcGIS for javascript 项目实战(环境监测系统)
    ArcGIS for JavaScript
    java语言从入门到精通2016+项目实训
    JavaSE高级篇---(IO流+多线程+XML+Socket+swing)
    JavaScript面向对象的编程视频课程第二季 对象
    学习java多线程的笔记3-使用BlockingQueue阻塞队列来模拟两个线程之间的通信
    13多线程与并发库之java5阻塞队列BlockingQueue的应用----子线程循环10次接着主线程循环100次接着又回到子线程循环10次接着再回到主线程循环100次如此循环50次
    13多线程与并发库之java5阻塞队列BlockingQueue的应用----子线程循环10次接着主线程循环100次接着又回到子线程循环10次接着再回到主线程循环100次如此循环50次
    java线程---BlockingQueue队列使用
    java线程系列---BlockingQueue队列的用法

    你可能感兴趣的:(java多线程)