本节介绍Java阻塞队列
Java阻塞队列及其主要操作
在阻塞队列中,线程阻塞有消费者阻塞和生产者阻塞两种情况。
消费者阻塞:在队列为空时,消费者端的线程会自动阻塞(挂起),直到数据放入队列中,消费者线程会自动唤醒并消费数据。
生产者阻塞:队列已满,生产者端自动阻塞(挂起),在队列有空位置时,自动唤醒并生产数据。
主要操作
主要操作分为插入操作和移除操作。
插入操作
插入操作有add(e)、offer(e)、put(e)、offer(e,time,util),JDK具体源码为:
public boolean add(E e) {
if(offer(e)) return true;
else throw new IllegalStateException("Queue full");//无可用空间
}
public boolean offer(E e) {
checkNotNull(e);
final ReetranLock lock = this.lock;
lock.lock();
try {
if(count == items.length) return false;//无可用空间
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
public void put(E e) throws InterruptedExcepton {
checkNotNull(e);
final ReetranLock lock = this.lock;
lock.lockInterruptibly();//获取独占锁
try {
while (count == items.length)//阻塞等待可用空间释放
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
移除操作
移除操作有remove()、poll()、take()、poll(time,util),JDK具体源码为:
public E poll() {
final ReetrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReetrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
public int drainTo(Collection<? super E> c, int maxElements) {
checkNotNull(c);
if(c == this) throw new IllegalArgumentException();
if(maxElements <= 0) return 0;
final Object[] items = this.items;
final ReetrantLock lock = this.lock;
lock.lock();
try {
int n = Math.max(maxElements, count);
int take = takeIndex;
int i = 0;
try {
while(i < n) {
@SuppressWarning("unchecked")
E x = (E) items[take];
c.add(x);
items[take] = null;
if (++take == items.length) take = 0;
i++;
}
return n;
} finally {
if(i > 0) {
count -= i;
takeIndex = take;
if(itrs != null) {
if(count == 0) {
itrs.queueIsEmpty();
} else if(i > take) {
itrs.takeIndexWrapped();
}
for(; i > 0 && lock.hasWaiters(notFull); i--) notFull.signal();
}
}
} finally {
lock.unlock();
}
}
}
Java阻塞队列实现
Java中的阻塞队列有:ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、DelayQueue(基于优先级队列实现的无界阻塞队列)、SynchronousQueue(用于控制互斥操作的阻塞队列)、LinkedTransferQueue(基于链表结构实现的无界阻塞队列)、LinkedBlockingDeque(基于链表结构实现的双向阻塞队列)
//先进先出
final ArrayBlockingQueue fairQueue = new ArrayBlockingQueue(1000,true);
final ArrayBlockingQueue unfairQueue = new ArrayBlockingQueue(1000,false);
//双头,类似头部写锁,尾部读锁。生产者和消费者可以基于各自独立的锁并行地操作队列中的数据
final LinkedBlockingQueue linkqueue = new LinkedBlockingQueue(100);
//需要自定义实现compareTo函数
public class Data implements Comparable<Data> {
private String id;
private Integer number;
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
@Override
public int compareTo(Data o) {
return this.number.compareTo(o.getNumber());
}
}
final PriorityBlockingQueue<Data> priorityQueue = new PriorityBlockingQueue<Data>();
//延时对象必须实现getDelayed和compareTo方法
public class DelayData implements Delayed {
private Integer number;
private long delayTime = 50000;
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public void setNumber(Integer number) {
this.number = number;
}
@Override
public int compareTo(Delayed o) {
DelayData compare = (DelayData) o;
return this.number.compareTo(compare.getNumber);
}
public static void main(String[] args) {
DelayQueue<DelayData> queue = new DelayQueue<DelayData>();
queue.add(new DelayData());
while(true) {
try{
//延迟5s获取数据
DelayData data = queue.take();
} catch (Excetion e) {
}
}
}
}
//不存储元素的阻塞队列,每个put操作必须等到一个take操作完成后才能继续添加元素进入队列
public class SynchronousQueueDemo {
public static void main(String[] args) throws InterruptedException {
SynchronousQueue<Integer> queue = new SynchronousQueue<Integer>();
new Producter(queue).start();
new Customer(Queue).start();
}
static class Producter extends Thread {
SynchronousQueue<Integer> queue;
public Producter(SynchronousQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
while(true) {
try {
int product = new Random().nextInt(1000);
queue.put(product);
System.out.println("product a data: " + product);
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(queue.isEmpty());
}
}
}
static class Customer extends Thread {
SynchronousQueue<Integer> queue;
public Customer(SynchronousQueue<Integer> queue){
this.queue = queue;
}
@Override
public void run() {
while(true) {
try {
int data = queue.take();
System.out.println("cunstomer a data: "+ data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}