BlockingQueue作为线程同步的工具,并不是作为一个容器使用,它具有一个特征:当生产者线程试图向其放入元素的时候,如果队列已满,则该线程被阻塞,当消费者线程试图从BlockingQueue中取出元素时,如果队列已空,则该线程阻塞。
BlockingQueue在jdk文档里面有如下几个方法:
抛出异常 | 特殊值 | 阻塞 | 超时 | |
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() | 不可用 | 不可用 |
BlockingQueue的实现子类有如下几个:
ArrayBlockingQueue:基于数组实现的阻塞队列,在创建ArrayBlockingQueue对象时必须制定容量大小。并且可以指定公平性与非公平性,默认情况下为非公平的,即不保证等待时间最长的队列最优先能够访问队列。
LinkedBlockingQueue:基于链表实现的阻塞队列,在创建LinkedBlockingQueue对象时如果不指定容量大小,则默认大小为Integer.MAX_VALUE。
PriorityBlockingQueue:以上2种队列都是先进先出队列,而PriorityBlockingQueue却不是,它会按照元素的优先级对元素进行排序,按照优先级顺序出队,每次出队的元素都是优先级最高的元素。注意,此阻塞队列为无界阻塞队列,即容量没有上限。
用Condition来模拟一个阻塞队列,假定有一个绑定的缓冲区,它支持 put
和 take
方法。如果试图在空的缓冲区上执行 take
操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put
操作,则在有空间变得可用之前,线程将一直阻塞。这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition实例来做到这一点
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length)
putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length)
takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
在多线程另一篇文章里面有一个题目(http://blog.csdn.net/erica_1230/article/details/38015291),启动三个线程循环十次交替打印出ABCABC,也可以用BlockingQueue来解决,代码如下:
package com.itcast.thread.blockingqueue;
import java.util.concurrent.*;
public class BlockingQueueOutput {
private BlockingQueue<Integer>bqA=new ArrayBlockingQueue<Integer>(1);
private BlockingQueue<Integer>bqB=new ArrayBlockingQueue<Integer>(1);
private BlockingQueue<Integer>bqC=new ArrayBlockingQueue<Integer>(1);
{
try {
bqB.put(1);
bqC.put(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void printA(){
try {
bqA.put(1);
System.out.print("A");
bqB.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void printB(){
try {
bqB.put(1);
System.out.print("B");
bqC.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void printC(){
try {
bqC.put(1);
System.out.print("C");
bqA.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TestBlockingQueueThread {
public static void main(String[] args) {
BlockingQueueOutput out=new BlockingQueueOutput();
A a=new A(out);
B b=new B(out);
C c=new C(out);
a.start();
b.start();
c.start();
}
}
跟以前的比是不是简洁了很多。
BlockingQueue也可以解决生产者和消费者问题:
package com.itcast.heima2;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueTest {
class Producer extends Thread{
private BlockingQueue<Integer>queue;
public Producer(BlockingQueue<Integer>queue){
this.queue=queue;
}
@Override
public void run() {
while(true){
try {
System.out.println(Thread.currentThread().getName()+" 准备生产 ");
Thread.sleep(200);
queue.put(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 生产完成: "+queue );
}
}
}
class Consumer extends Thread{
private BlockingQueue<Integer>queue;
public Consumer(BlockingQueue<Integer>queue){
this.queue=queue;
}
@Override
public void run() {
while(true){
try {
System.out.println(Thread.currentThread().getName()+" 准备消费 ");
Thread.sleep(200);
queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 消费完成: "+queue );
}
}
}
public static void main(String[] args) {
BlockingQueue<Integer>bq=new ArrayBlockingQueue<Integer>(1);
BlockingQueueTest test=new BlockingQueueTest();
//启动是3个生产者
test.new Producer(bq).start();
test.new Producer(bq).start();
test.new Producer(bq).start();
//启动一个消费者
test.new Consumer(bq).start();
}
}
打印结果:
Thread-0 准备生产
Thread-1 准备生产
Thread-2 准备生产
Thread-3 准备消费
Thread-2 生产完成: [1]
Thread-2 准备生产
Thread-3 消费完成: [1]
Thread-3 准备消费
Thread-0 生产完成: [1]
Thread-0 准备生产
Thread-3 消费完成: []
Thread-3 准备消费
Thread-1 生产完成: [1]
.......................................
只要一个线程向其中生产一个元素以后,其他的生产者线程都要等待,直到有消费者线程去消费为止。