学习目标
我们都知道在并发编程中,阻塞队列在多线程中的场景特别有用,比如在生产和消费者模型中,生产者生产数据到队列,队列满时需要阻塞线程,停止生产。消费者消费队列,对队列为空时阻塞线程停止消费,在Java中有提供不同场景的阻塞队列,那么接下来我们将学习
- ReentrantLock的Condition原理
- BlockingQueue的定义
- 了解ArrayBlockingQueue的实现
- 如何手写一个阻塞队列
Condition原理
在学习阻塞队列之前,我们先需要弄清楚ReentrantLock
的Condition
机制。我们知道使用synchronized
结合Object上的wait和notify方法可以实现线程间的等待通知机制。Condition同样可以实现这个功能,而且相比前者使用起来更清晰也更简单,扩展性更好。
- Condition能够支持不响应中断,而通过使用Object方式不支持
- Condition能够支持多个等待队列(new多个Condition对象),而Object方式只能支持一个
- Condition能够支持超时时间的设置,而Object不支持
具体看个小例子:
ReentrantLock lock = new ReentrantLock();
Condition waitCond = lock.newCondition();
Thread t1 = new Thread(() -> {
System.out.println("before-wait...1");
try {
lock.lock();
waitCond.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
System.out.println("after-wait...1");
});
Thread t2 = new Thread(() -> {
System.out.println("before-wait...2");
try {
lock.lock();
waitCond.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
System.out.println("after-wait...2");
});
t1.start();
t2.start();
Thread.sleep(1);
lock.lock();
waitCond.signalAll();
System.out.println("signalAll");
lock.unlock();
输出
before-wait...2
before-wait...1
signalAll
after-wait...2
after-wait...1
Process finished with exit code 0
可以看到,想要获得一个Condition对象,需要首先通过一个ReentrantLock锁来创建,而最终调用是AQS
中的内部类Cond