如果队列满了,添加元素的线程将会陷入等待状态,而队列为空,获取元素的线程将会陷入等待。有了BlockingQueue,我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程。这一切都交给了BlockingQueue。
- ArrayBlockingQueue
数组结构组成的游街阻塞队列
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
初始化需要传递容器大小,即数组大小,还有获取元素的线程是否公平,即ReentrantLock构造方法中的参数。
添加元素
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
checkNotNull(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
//等待时间
while (count == items.length) {
if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
//将元素添加到数组中,并且唤醒取线程
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
获取元素方法
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
//等待
while (count == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
//从数组中获取元素,唤醒添加线程。
return dequeue();
} finally {
lock.unlock();
}
}
ArrayBlockingQueue与LinkedBlockingQueue
- LinkedBlockingQueue
链表组成的有界队列
添加元素
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException();
long nanos = unit.toNanos(timeout);
int c = -1;
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {
//当前链表容量等于最大容量,进入循环
if (nanos <= 0)
return false;
//陷入等待
nanos = notFull.awaitNanos(nanos);
}
//可以添加元素
enqueue(new Node<E>(e));
c = count.getAndIncrement();
if (c + 1 < capacity)
//添加元素后没有达到最大的容量阈值,唤醒阻塞在notFull的线程
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
//c为添加之前的链表元素个数。c=0说明添加元素之前,执行拿走线程陷入等待状态,
//需要唤醒他们去拿走添加的元素
//可能之前元素充足,各个取线程没有陷入等待,如果没有c==0判断,signalNotEmpty执行没有意义,因为压根就没有线程陷入等待
// 参考
signalNotEmpty();
return true;
}
拉取元素方法
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
E x = null;
int c = -1;
long nanos = unit.toNanos(timeout);
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
if (nanos <= 0)
return null;
// 链表元素个数为空,陷入等待
nanos = notEmpty.awaitNanos(nanos);
}
//出队列
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
//唤醒拿线程
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
//唤醒添加线程
signalNotFull();
return x;
}
- DelayQueue
延迟无界阻塞队列,类似于RabbitMq的延迟队列,使用案例如下
BlockingQueue<DelayedItem> blockingQueue=new DelayQueue<>();
//设置延迟5秒钟
blockingQueue.add(new DelayedItem(5*1000L));
long beginTime = System.currentTimeMillis();
System.out.println(beginTime);
DelayedItem poll = blockingQueue.poll(60,TimeUnit.SECONDS);
System.out.println("延迟时间:"+(System.currentTimeMillis()-beginTime));
System.out.println("获取到的任务,延迟时间:"+poll.getDelayTime());
public static class DelayedItem implements Delayed{
/**
* 延迟时间
*/
private Long delayTime;
/**
* 到期时间
*/
private Long expireTime;
public DelayedItem(Long delayTime) {
this.delayTime = delayTime;
this.expireTime=System.currentTimeMillis()+delayTime;
}
public Long getDelayTime() {
return delayTime;
}
@Override
public int compareTo(Delayed o) {
return (int) (this.getDelay(TimeUnit.MILLISECONDS)-o.getDelay(TimeUnit.MILLISECONDS));
}
@Override
public long getDelay(TimeUnit unit) {
return expireTime-System.currentTimeMillis();
}
}
DelayQueue源码解析
添加任务
public boolean offer(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//将e添加到合适的位置,如果构造DelayQueue定义了比较器,会用到Comparator,没有定义比较器,那就用到实现的compareTo方法
//决定那个任务放到队列中的先后顺序。
q.offer(e);
if (q.peek() == e) {
leader = null;
available.signal();
}
return true;
} finally {
lock.unlock();
}
}
获取数据
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
E first = q.peek();
if (first == null) {
if (nanos <= 0)
return null;
else
//没有任务,陷入等待,
nanos = available.awaitNanos(nanos);
} else {
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0)
//获取到的任务延迟时间到了,拉取出来。
return q.poll();
if (nanos <= 0)
//等待的时间到了,直接返回。
return null;
first = null; // don't retain ref while waiting
if (nanos < delay || leader != null)
//任务的延迟时间比等待的数据长,再等待一会。
nanos = available.awaitNanos(nanos);
else {
Thread thisThread = Thread.currentThread();
leader = thisThread;
try {
//任务的延迟时间比等待的数据短,等待任务的延迟数据,
long timeLeft = available.awaitNanos(delay);
nanos -= delay - timeLeft;
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
if (leader == null && q.peek() != null)
available.signal();
lock.unlock();
}
}
SynchronousQueue
不存储元素的阻塞队列