Java并发编程:阻塞队列
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。
Java 1.5之后,在java.util.concurrent包下提供了若干个阻塞队列
ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
简单的例子:创建两个线程用来存放数据,一个线程用来取数据,用阻塞队列BlockingQueue实现。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueTest {
public static void main(String[] args) {
final BlockingQueue queue = new ArrayBlockingQueue(3);
for (int i = 0; i < 2; i++) {
new Thread() {
public void run() {
while (true) {
try {
Thread.sleep((long) (Math.random() * 1000));
System.out.println(Thread.currentThread().getName()
+ "准备放数据!");
queue.put(1);
System.out.println(Thread.currentThread().getName()
+ "已经放了数据," + "队列目前有" + queue.size()
+ "个数据");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
new Thread() {
public void run() {
while (true) {
try {
// 将此处的睡眠时间分别改为100和1000,观察运行结果
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()
+ "准备取数据!");
queue.take();
System.out.println(Thread.currentThread().getName()
+ "已经取走数据," + "队列目前有" + queue.size() + "个数据");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
用阻塞队列改写上一个程序程序:
子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次。
import java.util.Collections;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueCommunication {
public static void main(String[] args) {
final Bussiness bussiness = new Bussiness();
new Thread(new Runnable() {
public void run() {
for (int i = 1; i <= 50; i++) {
bussiness.sub(i);
}
}
}).start();
new Thread(new Runnable() {
public void run() {
for (int i = 1; i <= 500; i++) {
bussiness.main(i);
}
}
}).start();
}
static class Bussiness {
BlockingQueue<Integer> queue1 = new ArrayBlockingQueue<Integer>(1); // 管理子线程
BlockingQueue<Integer> queue2 = new ArrayBlockingQueue<Integer>(1); // 管理主线程
{
try {
queue2.put(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void sub(int i) {
try {
queue1.put(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int j = 1; j <= 10; j++) {
System.out.println("sub thread sequece of " + j + ",loop of "
+ i);
}
try {
queue2.take();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void main(int i) {
try {
queue2.put(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int j = 1; j <= 100; j++) {
System.out.println("main thread sequece of " + j + ",loop of "
+ i);
}
try {
queue1.take();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
阻塞队列使用最经典的场景就是socket客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。还有其他类似的场景,只要符合生产者-消费者模型的都可以使用阻塞队列。