(译)Java Concurrent系列--BlockingQueue

来源:互联网 发布:如何安装php开发环境 编辑:程序博客网 时间:2024/04/30 10:08

java.util.concurrent包中的BlockingQueue接口是一个能够线程安全的插入和取出对象实例的阻塞队列。这篇文章将展示如何使用BlockingQueue

本文不会讨论如何利用Java去实现一个BlockingQueue。如果你有兴趣想去自己实现,你可以参考Java Concurrency Tutorial里面关于Blocking Queue部分的内容。

  • BlockingQueue Usage
    BlockingQueue通常用于一个线程生产对象而另外一个线程消费这些对象的情景。下图是对这个原理的阐述:
    ![BlockingQueue原理][http://tutorials.jenkov.com/images/java-concurrency-utils/blocking-queue.png]

    生产线程会持续产生新对象并将其插入到阻塞队列之中,直到队列达到它存储容量的临界点。也就是说,阻塞队列的容量是有限的。如果阻塞队列到达了存储的临界点,当生产线程尝试插入新的对象时将会一直阻塞,直到消费线程从阻塞队列中取出一个对象。
    消费线程则会持续的从阻塞队列取出对象并进行处理。当消费线程试着从一个空的队列取一个对象时,它会一直阻塞直到生产线程将一个对象放入队列中。

  • BlockingQueue Methods
    BlockingQueue有4组不同的方法用于插入,删除和检查队列中的对象。如果请求的方法不能够立即执行时,每组方法的结果也是不同的。下表展示了这些方法的返回结果。

  Throws Exception Special Value Blocks Times Out Insert add(o) offer(o) put(o) offer(o, timeout, timeunit) Remove remove(o) poll() take() poll(timeout, timeunit) Examine element() peek()

4组不同行为方法的解释如下:
1. Throw Exception: 如果试图调用的操作无法立即执行,则抛出一个异常。
2. Special Value: 如果试图调用的操作无法立即执行,则返回一个特殊值(通常是true/false)。
3. Blocks: 如果试图调用的操作无法立即执行,该方法调用会一直阻塞直到可以立即执行为止。
4. Times Out: 如果试图调用的操作无法立即执行,该方法调用会一直阻塞直到可以立即执行为止,但是等待时间不会超过给定的时间间隔(timeout)。返回一个特定值来表示该方法是否调用成功(通常是true/false)。
BlockingQueue中不能插入null。如果你试图插入一个null, BlockingQueue将会抛出NullPointerException异常。
BlcokingQueue内部所有元素都可以被访问,而不仅仅是头部和尾部的元素。例如,你将一个对象放入队列中等待处理,但你的应用想取消这个任务。这时,你就可以调用诸如remove(o)方法来删除队列中的特定元素。但是这样的操作效率不会很高,因此,除非你迫不得已,否则尽量不要使用这类方法。

  • BlockingQueue Implementations
    BlockingQueue是个接口,你需要使用它的实现类来使用它。java.util.concurrent包中BlockingQueue接口的实现类如下(原文中为Java 6,译者基于Java 8展示):
    ArrayBlockingQueue
    DelayQueue
    LinkedBlcokingQueue
    PriorityBlockingQueue
    SynchronousQueue

  • Java BlockingQueue Example
    下面展示了一个BlockingQueue的例子。例子中使用了BlockingQueue接口的实现类之一–ArrayBlockingQueue
    首先,BlockingQueueExample类在不同的线程中分别启动了一个生产者和一个消费者。生产者向共享的BlockingQueue中插入字符串,消费者从共享的BlockingQueue中取出字符串。

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);    }}

下面是生产者类。注意它在每次put()调用时是如何休眠一秒钟的。这讲使得消费者在等待取出队列中对象时发生阻塞。

public class Producer implements Runnable{    protected BlockingQueue queue = null;    public Producer(BlockingQueue queue) {        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();        }    }}

下面是消费者类。它只是从队列中取出对象,然后将它们打印到System.out

public class Consumer implements Runnable{    protected BlockingQueue queue = null;    public Consumer(BlockingQueue queue) {        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();        }    }}

原文链接