您的位置:首页 > 产品设计 > UI/UE

(译)Java Concurrent系列--BlockingQueue

2017-08-30 14:19 281 查看
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 ExceptionSpecial ValueBlocksTimes Out
Insertadd(o)offer(o)put(o)offer(o, timeout, timeunit)
Removeremove(o)poll()take()poll(timeout, timeunit)
Examineelement()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();
}
}
}


原文链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java concurrent