Ch10-Java Collections 之 LinkedBlockingQueue
February 5, 2020
java.util.concurrent.LinkedBlockingQueue
LinkedBlockingQueue 是基于一个“two lock queue”算法实现的,具体参考Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms。这篇文章为了提升在多处理器的机器上的更好性能的并发而提出了这个算法,其中心思想是:通过两把锁分别控制并发,入队时:只需要锁 Tail Node,出队时,只需要锁 Head Node。
1. 添加 #
操作 | 操作成功 | 操作失败 |
---|---|---|
offer | 返回 true | 队列已满,返回 false |
add | 返回 true | 队列已满,抛异常 |
put | 不返回 | 队列已满,阻塞 |
1.1 put 说明 #
首先获取 putLock 对队列进行进行加锁,如果队列已满,那么将当前线程放入到 notFull 这个条件队列里面。如果队列没有满,那么入队成功,并试着唤醒 notFull 里面的一个线程。最后释放 putLock。
注意
- put 线程在队列没有满时会自己直接唤醒其他 put 线程,如果没有等待的 put 线程,直接结束了。如果有就直到队列元素已满才结束挂起。这也是为什么 LinkedBlockingQueue 的吞吐量要相对大些的原因。
- 队列当前大小为 0,则会主动唤醒 notEmpty 这个条件队列里面的线程,防止线程饿死。
2. 获取 #
操作 | 操作成功 | 操作失败 |
---|---|---|
remove | 返回 true | 队列为空,返回 false |
poll | 返回元素 | 队列为空,返回 nul。 |
take | 返回元素 | 队列为空,阻塞 |
2.1 take 说明 #
首先获取 takeLock 对队列进行加锁,如果队列为空,则将当前线程放到 notEmpty 这个条件队列里面。如果队列不为空,那么出队成功,并试着唤醒 notEmpty 里面的一个线程。最后释放 takeLock。
注意
- take 线程在队列没有满时会自己直接唤醒其他 take 线程,如果没有等待的 take 线程,直接结束了。如果有就直到队列元素已满才结束挂起。这也是为什么 LinkedBlockingQueue 的吞吐量要相对大些的原因。
- 队列当前大小为 0,则会主动唤醒 notFull 这个条件队列里面的线程,防止写线程饿死。