面试时曾经被问过阻塞队列吗?
想必很多人面试时有被问到阻塞队列的经历。我们经常会在各种代码中见到或者用到它,最经常见到的地方就是线程池。
但是如果问起阻塞队列的原理,它是基于什么实现的,你是否说的上来呢?
阻塞队列(BlockingQueue)其实也是队列,但是它有两个特点, · 当队列满时,往队列的put()操作会导致当前线程阻塞 · 当队列空时,向队列的take()操作也会导致当前线程阻塞
BlockingQueue经常用在以下几个场景 · 生产者&消费者 · 线程间通信 · 线程池
相信很多人都知道,add()其实并不是阻塞操作,当队列满时add()会抛出异常,而put()不会抛出异常。
看过上一篇文章的朋友肯定立马想到BlockingQueue是基于Condition,我们可以用很简单的代码写出阻塞队列的原理
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();
}
}
以put()为例说明,当队列满时,当前线程会等待notFull条件满足,若不满足则持续等待。直到有take()操作,队列的notFull条件满足,才会往队列放对象,同时让notEmpty条件满足,对应的take()操作才能正常进行。
看完这篇文章,相信你已经明白阻塞队列的实现原理了吧。以下是它的主要子类 · ArrayBlockingQueue · LinkedBlockingQueue · SynchronousQueue 虽然它们的具体实现各不相同,但是原理都是一样基于Condition去实现的。
下次面试时被问到BlockingQueue的话就可以淡定的说啦! 欢迎订阅关注!