Blocking Queue
一、阻塞队列
BlockingQueue是Java并发包的中的一个接口,支持在多线程环境中数据的存储和传递。
核心特性
- 阻塞插入和移除:如果队列满了,试图添加新元素的操作将会被阻塞(进入等待队列),直到有足够的空间(等待signal唤醒)。同样地,如果队列为空,试图移除元素的操作也会被阻塞(进入等待队列),直到队列中有元素(等待signal唤醒)。
- 线程安全:所有操作都是线程安全的,无需额外同步机制。
- 不允许存储null值:因为poll()方法返回null表示队列为空,所以不允许存储null值以避免混淆。
- 可选的容量限制:有些实现允许指定最大容量,而其他则是无界的(例如LinkedBlockingQueue默认构造函数创建的是无界队列)
BlockingQueue原理
- BlockingQueue的内部通常通过锁(如ReentrantLock)和条件变量(Condition)来实现线程间的同步。当一个线程尝试对一个已满或已空的队列执行操作时,该线程会被挂起,直到另一个线程改变队列的状态(即增加或移除元素)。这个过程涉及到以下关键点:
- 锁:用于确保同一时刻只有一个线程能够修改队列状态。
- 条件变量:用于让线程在特定条件下等待(比如队列为空或满),并且可以在条件满足时重新唤醒这些线程。
-
例如
ArrayBlockingQueue的实现原理
-
核心成员,主要包含
一个lock和两个Condition条件控制(一个Condition一个等待队列)
- final ReentrantLock lock; 重入锁,用来保护对队列的所有操作。
- private final Condition notEmpty; 当队列为空时,等待获取元素的线程会在此条件上等待。
- private final Condition notFull; 当队列已满时,等待插入元素的线程会在此条件上等待。
- 内部逻辑细节
- 环形数组:为了高效利用数组空间,ArrayBlockingQueue实际上实现了环形数组的概念。即当putIndex或takeIndex到达数组末尾时,它们会被重置为0,从而形成一个循环结构
- put
- count==items.length,表示队列满了,等待插入元素的线程会在此条件进入等待
- enqueue(),元素入队列,同时唤醒在notEmpty条件等待的线程
- take
- count==0,表示队列空了,等待获取元素的线程会在此条件上等待
- dequeue(),元素出队列,同时唤醒在notFull条件等待的线程
-
核心成员,主要包含
一个lock和两个Condition条件控制(一个Condition一个等待队列)