Chinaunix首页 | 论坛 | 博客
  • 博客访问: 255416
  • 博文数量: 164
  • 博客积分: 60
  • 博客等级: 民兵
  • 技术积分: 1129
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-09 21:55
文章分类

全部博文(164)

文章存档

2017年(2)

2015年(67)

2014年(95)

我的朋友

分类: Java

2015-05-06 19:00:51

/**

    本例介绍一个特殊的队列:BlockingQueue,如果BlockQueue是空的,BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒.同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间才会被唤醒继续操作.

    本例再次实现11.4线程----条件Condition中介绍的篮子程序,不过这个篮子中最多能放的苹果数不是1,可以随意指定.当篮子满时,生产者进入等待状态,当篮子空时,消费者等待.

 */

/**

    使用BlockingQueue的关键技术点如下:

    1.BlockingQueue定义的常用方法如下:

        1)add(anObject):anObject加到BlockingQueue,即如果BlockingQueue可以容纳,则返回true,否则招聘异常

        2)offer(anObject):表示如果可能的话,anObject加到BlockingQueue,即如果BlockingQueue可以容纳,则返回true,否则返回false.

        3)put(anObject):anObject加到BlockingQueue,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续.

        4)poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null

        5)take():取走BlockingQueue里排在首位的对象,BlockingQueue为空,阻断进入等待状态直到Blocking有新的对象被加入为止

  

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

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

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

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

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

点击(此处)折叠或打开

  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. }
 执行结果:
  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包是个强大的包!

阅读(692) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~