学习ConcurrentLinkedDeque源码

可以看到ConcurrentLinkedDeque实现的接口有Serializable, Iterable<E>, Collection<E>, Deque<E>, Queue<E>,相应的就有各个接口实现的特性,这个类比较突出的特性可能是Concurrent这个词啦。

基于链接节点的无界ConcurrentLinkedDeque(并发双端队列)。并发插入,删除和访问操作可跨多个线程安全执行。当许多线程共享对公共集合的访问权时,ConcurrentLinkedDeque是一个合适的选择。与大多数其他并发集合实现一样,此类不允许使用null元素。

其中Iterators 和 spliterators 是弱一致的。

主要有两个属性字段,head表示队列的队首元素,tail表示队尾。

在网上copy一个图:

ConcurrentLinkedDeque的构造函数只有两个

ConcurrentLinkedDeque当然可以用来当queue和stack实现来用,但是我们主要来看看deque的接口实现,前后两种方法实现的方式一样的,但是返回值会有区分。

队首入队 addFirst(e) offerFirst(e)
队首出队 removeFirst() pollFirst()
队首读取 getFirst() peekFirst()
队尾入队 addLast(e) offerLast(e)
队尾出队 removeLast() pollLast()
队尾读取 getLast() peekLast()

队首入队,用的都是private void linkFirst(E e) ,这里会先创建一个newNode,然后使用CAS方式入队,这里感到奇怪的p = h,q这个写法,那么这是只是定义一个名字,然后告诉他你是什么类型?这好有迷惑性呀。队尾入队也是类似的,我想这个算法极端情况的效率怎么样呢?

让我们看看出队的操作吧,然后执行unlink操作,删除元素,里面的操作还是有点复杂的。队尾的操作也类似。

读取操作比上面的操作应该简单一些吧,其中有个succ操作来获取队首元素。

请注意,与大多数集合不同,size方法不是恒定时间操作。由于这些deques的异步性质,确定元素的当前数量需要遍历元素,因此如果在遍历期间修改此集合,则可能报告不准确的结果。备注里面还写着在并发操作中,可能这个方法没什么用。不过这里p ==(p=p.next)是什么情况?

添加,删除或检查多个元素的批量操作,例如addAll(java.util.Collection <?extends E>),removeIf(java.util.function.Predicate <?super E>)或forEach(java.util。function.Consumer <?super E>),不保证以原子方式执行。例如,与addAll操作并发的forEach遍历可能只会观察到一些添加的元素。

参考:

https://www.jianshu.com/p/602b3240afaf

https://blog.csdn.net/chenleixing/article/details/44143641

https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/ConcurrentLinkedDeque.html

https://segmentfault.com/a/1190000016284649

猜你喜欢

转载自my.oschina.net/u/2277632/blog/2980321