三.多线程JUC篇-3.26 LinkedTransferQueue

1.前言

前面提到的各种BlockingQueue对读或者写都是锁上整个队列,在并发量大的时候,各种锁是比较耗资源和耗时间的,而前面的SynchronousQueue虽然不会锁住整个队列,但它是一个没有容量的“队列”,那么有没有这样一种队列,它即可以像其他的BlockingQueue一样有容量又可以像SynchronousQueue一样不会锁住整个队列呢?有!答案就是LinkedTransferQueue。

2.介绍

  • LinkedTransferQueue是基于链表的FIFO无界阻塞队列,它出现在JDK7中。
    Doug Lea 大神说LinkedTransferQueue是一个聪明的队列。它是ConcurrentLinkedQueue、SynchronousQueue (公平模式下)、无界的LinkedBlockingQueues等的超集。

  • LinkedTransferQueue采用一种预占模式。
    (1) 当有消费进线程阻塞等待时,调用transfer方法的生产者线程不会将元素存入队列,而是直接将元素传递给消费者
    (2) 如果调用transfer方法的生产者线程发现没有正在等待的消费者线程,则会将元素入队,然后会阻塞等待,直到有一个消费者线程来获取该元素

3.API

3.1 transfer(E e)

若当前存在一个正在等待获取的消费者线程,即立刻移交之;否则,会插入当前元素 e 到队列尾部,并且等待进入阻塞状态,到有消费者线程取走该元素。

3.2 tryTransfer(E e)

若当前存在一个正在等待获取的消费者线程(使用 take() 或者 poll() 函数),使用该方法会即刻转移 / 传输对象元素 e ;若不存在,则返回 false ,并且不进入队列。这是一个不阻塞的操作。

3.3 tryTransfer(E e, long timeout, TimeUnit unit)

若当前存在一个正在等待获取的消费者线程,会立即传输给它 ; 否则将插入元素 e 到队列尾部,并且等待被消费者线程获取消费掉 , 若在指定的时间内元素 e 无法被消费者线程获取,则返回 false ,同时该元素被移除。

3.4 hasWaitingConsumer()

判断是否存在消费者线程

3.5 getWaitingConsumerCount()

获取所有等待获取元素的消费线程数量

3.6 size()

因为队列的异步特性,检测当前队列的元素个数需要逐一迭代,可能会得到一个不太准确的结果,尤其是在遍历时有可能队列发生更改。

3.6 批量操作

类似于addAll,removeAll,retainAll, containsAll, equals, toArray 等方法,API不能保证一定会立刻执行。

4 总结

LinkedTransferQueue是 SynchronousQueue 和 LinkedBlockingQueue 的合体,性能比 LinkedBlockingQueue 更高(没有锁操作),比 SynchronousQueue能存储更多的元素。

  • 当 put 时,如果有等待的线程,就直接将元素 “交给” 等待者, 否则直接进入队列。
  • put和 transfer 方法的区别是,put 是立即返回的, transfer 是阻塞等待消费者拿到数据才返回。transfer方法和 SynchronousQueue的 put 方法类似。

猜你喜欢

转载自blog.csdn.net/weixin_42868638/article/details/112234099