阻塞队列 BlockingQueue

白玉 IT哈哈

BlockingQueue用法

BlockingQueue通常用于一个线程生产对象,而另外一个线程消费这些对象的场景。下图是对这个原理的阐述:
阻塞队列 BlockingQueue

一个线程往里边放,另外一个线程从里边取的一个BlockingQueue

一个线程将会持续生产新对象并将其插入到队列之中,直到队列达到它所能容纳的临界点。也就是说,它是有限的。如果该阻塞队列到达了其临界点,负责生产的线程将会在往里边插入新对象时发生阻塞。它会一直处于阻塞之中,直到负责消费的线程从队列中拿走一个对象。负责消费的线程将会一直从该阻塞队列中拿出对象。如果消费线程尝试去从一个空的队列中提取对象的话,这个消费线程将会处于阻塞之中,直到一个生产线程把一个对象丢进队列。

BlockingQueue的方法

BlockingQueue具有4组不同的方法用于插入、移除以及对队列中的元素进行检查。如果请求的操作不能得到立即执行的话,每个方法的表现也不同。这些方法如下:
阻塞队列 BlockingQueue

四组不同的行为方式解释:

  1. 抛异常:如果试图的操作无法立即执行,抛一个异常。
  2. 特定值:如果试图的操作无法立即执行,返回一个特定的值(常常是true/false)。
  3. 阻塞:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。
  4. 超时:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。返回一个特定值以告知该操作是否成功(典型的是true/false)。

无法向一个BlockingQueue中插入null。如果你试图插入null,BlockingQueue将会抛出一个NullPointerException。

可以访问到BlockingQueue中的所有元素,而不仅仅是开始和结束的元素。比如说,你将一个对象放入队列之中以等待处理,但你的应用想要将其取消掉。那么你可以调用诸如remove(o)方法来将队列之中的特定对象进行移除。但是这么干效率并不高(译者注:基于队列的数据结构,获取除开始或结束位置的其他对象的效率不会太高),因此你尽量不要用这一类的方法,除非你确实不得不那么做。

BlockingQueue的实现

BlockingQueue是个接口,你需要使用它的实现之一来使用BlockingQueue。
java.util.concurrent具有以下BlockingQueue接口的实现(Java6):

1. lArrayBlockingQueue
1. lDelayQueue
1. lLinkedBlockingQueue
1. lPriorityBlockingQueue
1. lSynchronousQueue

Java中使用BlockingQueue的例子

这里是一个Java中使用BlockingQueue的示例。本示例使用的是BlockingQueue接口的ArrayBlockingQueue实现。

首先,BlockingQueueExample类分别在两个独立的线程中启动了一个Producer和一个Consumer。Producer向一个共享的BlockingQueue中注入字符串,而Consumer则会从中把它们拿出来。

public class BlockingQueueExample{   public static void main(String[] args) throws Exception{      BlockingQueue queue = new ArrayBlockingQueue(1024);      Producer producer = new Producer(queue);      Consumer consumer = new Consumer(queue);      new Thread(producer).start();      new Thread(consumer).start();      Thread.sleep(4000);   }}

以下是Producer类。注意它在每次put()调用时是如何休眠一秒钟的。这将导致Consumer在等待队列中对象的时候发生阻塞。

public  class  Producer implements Runnable{    protected  BlockingQueue  queue = null;    public Producer(BlockingQueuequeue){        this.queue=queue;    }    public void run(){        try{            queue.put("1");            Thread.sleep(1000);            queue.put("2");            Thread.sleep(1000);            queue.put("3");        }catch(InterruptedException e){            e.printStackTrace();        }    }}

以下是Consumer类。它只是把对象从队列中抽取出来,然后将它们打印到System.out。

public  class  Consumer  implements  Runnable{    protected  BlockingQueue  queue = null;    public Consumer(BlockingQueuequeue){        this.queue=queue;    }    public void run(){        try{            System.out.println(queue.take());            System.out.println(queue.take());            System.out.println(queue.take());        }catch(InterruptedException e){            e.printStackTrace();        }    }}

更多相关文章

  1. java中的几个线程池的使用
  2. (不谈废话,只有干货)解决线程间协作问题的工具类Exchanger详解
  3. 一文看懂 Node.js 中的多线程和多进程[每日前端夜话0x107]
  4. 如何停止一个线程池?
  5. Java 中线程池包含哪些状态?
  6. 如何创建、启动 Java 线程?
  7. Executors如何创建线程池?
  8. 什么是线程?什么是进程?为什么要有线程?有什么关系与区别?
  9. 什么是线程池?

随机推荐

  1. Android的信号格数显示优化
  2. Android监听消息通知栏点击事件
  3. 分享到某个地方
  4. 使用 Android 和 XML 构建动态用户界面
  5. arm-linux-androideabi-gcc 4.8的选项分
  6. Android UI开发第六篇——仿QQ的滑动Tab
  7. Android:Manifest merger failed with mu
  8. Android多媒体开发 Pro Android(安卓)Med
  9. Android画图 Bitmap
  10. 简单的Android日志文件记录类