并发编程——-LinkedTransferQueue
Java 中总的算起来有 8 种阻塞队列。
我们分析了:
- 并发编程之 SynchronousQueue 核心源码分析
- 并发编程之 ConcurrentLinkedQueue 源码剖析
- 并发编程之 LinkedBolckingQueue 源码剖析
- 在 并发编程 —— ScheduledThreadPoolExecutor 中顺带分析了 DelayWorkQueue。
ArrayBlockingQueue
数组队列,我们在 使用 ReentrantLock 和 Condition 实现一个阻塞队列 看过了 JDK 写的一个例子,就是该类的基本原理和实现。楼主不准备分析了。
LinkedBlockingDeque
是一个双向链表的队列。常用于 “工作窃取算法”,有机会再分析。
DelayQueue
是一个支持延时获取元素的无界阻塞队列。内部用 PriorityQueue
实现。有机会再分析。
PriorityBlockingQueue
是一个支持优先级的无界阻塞队列,和 DelayWorkQueue
类似。有机会再分析。
今天要分析的是剩下的一个比较有意思的队列:LinkedTransferQueue
。
为什么说有意思呢?他可以算是 LinkedBolckingQueue
和 SynchronousQueue
和合体。
我们知道 SynchronousQueue
内部无法存储元素,当要添加元素的时候,需要阻塞,不够完美,LinkedBolckingQueue
则内部使用了大量的锁,性能不高。
两两结合,岂不完美?性能又高,又不阻塞。
我们一起来看看。
2. LinkedTransferQueue 介绍
该类实现了一个 TransferQueue。该接口定义了几个方法:
1 | public interface TransferQueue<E> extends BlockingQueue<E> { |
相比较普通的阻塞队列,增加了这么几个方法。
3. 关键源码分析
阻塞队列不外乎put ,take,offer ,poll
等方法,再加上TransferQueue
的 几个 tryTransfer
方法。我们看看这几个方法的实现。
put
方法:
1 | public void put(E e) { |
take
方法:
1 | public E take() throws InterruptedException { |
offer
方法:
1 | public boolean offer(E e) { |
poll
方法:
1 | public E poll() { |
tryTransfer
方法:
1 | public boolean tryTransfer(E e) { |
transfer
方法:
1 | public void transfer(E e) throws InterruptedException { |
可怕,所有方法都指向了 xfer
方法,只不过传入的不同的参数。
第一个参数,如果是 put
类型,就是实际的值,反之就是 null。
第二个参数,是否包含数据,put 类型就是 true,take 就是 false。
第三个参数,执行类型,有立即返回的 NOW
,有异步的 ASYNC
,有阻塞的 SYNC
, 有带超时的 TIMED
。
第四个参数,只有在 TIMED
类型才有作用。
So,这个类的关键方法就是 xfer 方法了。
4. xfer 方法分析
源码加注释:
1 | private E xfer(E e, boolean haveData, int how, long nanos) { |
代码有点长,其实逻辑很简单。
逻辑如下:
找到 head
节点,如果 head
节点是匹配的操作,就直接赋值,如果不是,添加到队列中。
注意:队列中永远只有一种类型的操作,要么是 put
类型, 要么是 take
类型.
整个过程如下图:
相比较 SynchronousQueue
多了一个可以存储的队列,相比较 LinkedBlockingQueue
多了直接传递元素,少了用锁来同步。
性能更高,用处更大。
5. 总结
LinkedTransferQueue
是 SynchronousQueue
和 LinkedBlockingQueue
的合体,性能比 LinkedBlockingQueue
更高(没有锁操作),比 SynchronousQueue
能存储更多的元素。
当 put
时,如果有等待的线程,就直接将元素 “交给” 等待者, 否则直接进入队列。
put
和 transfer
方法的区别是,put 是立即返回的, transfer 是阻塞等待消费者拿到数据才返回。transfer
方法和 SynchronousQueue
的 put 方法类似。