jdk concurrent collection---ConcurrentLinkedQueue原理分析
2009-11-30 11:36
633 查看
另一个值得一提的Concurrent是ConcurrentLinkedQueue。这个类采用了另一种提高并发度的方式:非阻塞算法(Non-blocking),第一次实现了无锁的并发。
谈到这里,先要介绍一下非阻塞算法。其实非阻塞算法并不是什么神秘高深的东西,它需要有一套硬件和指令的配合(似乎目前大多数pc都能支持),主要解决的
问题是:在许多时候,一个线程A持有其他线程B,C,D所需要的资源,但线程A遭遇网络阻塞,或数据库连接阻塞,或页面阻塞等。这时B,C,D就必须等待
A执行结束才能继续向前推进。这种情况在队列、堆栈等数据结构中也会经常出现,典型的如将一个队列中的数据取出来需要锁整个队列,也就是说,在对队列的操
作中,各个线程实际上是串行的,中间还需要加上线程上下文切换的开销。如何在取队列中元素时进一步提高并发度(就像ConcurrentHashMap一
样只锁部分)。ConcurrentHashMap是固定的16个段,并且每个段的操作是独立的,所以每个段使用了一把锁,关于这点也是考虑到一些开销和
安全的问题,而队列中元素则是可以动态增长的,因为要涉及到队列指针的问题,不是锁单独一个元素就能够保证其原子性的。这时传说中的非阻塞算法就是比较好
的选择了。
非阻塞算法
在《Concurrency in
practice》中对两个概念nonblocking和lock-free进行了解释。nonblocking定义为:任何线程失败或挂起不影响其他线
程的失败或挂起;而lock-free定义为:在执行的的每一步,都有线程能够向前推进。而一个基于CAS(compareAndSet)且构造正确的算
法一定是nonblocking和lock-free的。
对于java中的非阻塞算法,核心原理是采用硬件级的指令来保证CAS的原子性,不同于lock这样的悲观锁定,非阻塞算法是乐观的,它基于某些算法步骤
是不安全的,在每次进行CAS时可能成功,也可能失败,失败则再取新值重新CAS,这样不用每次使用lock以保证得到锁的线程必须成功。
一个比较好的例子是Java 理论与实践: 非阻塞算法简介
中的Nonblocking
stack,这里采用的是Treiber
的非阻塞算法。这个例子比较容易,之后有一个对ConcurrentLinkedQueue的put方法介绍的例子,这里又是采用的Michael-Scott算法
。
开发非阻塞算法是一项非常有挑战的任务,对一个算法中的每一步都需要证明不会产生冲突和死锁。当然,也遵循一些规律,首先无论是否在多线程的多步执行中必
须使得数据结构总是在一致的状态。即一个线程不能打断另一个线程的原子操作。其次,假设一个线程执行更新,另一个线程等待更新,如果前一个线程更新失败,
则后一个线程会浪费等待时间,并且在等待中没有任何向前推进。解决的办法是细化原子操作的粒度,并且后一个线程使用快照。
@ThreadSafe public class LinkedQueue <E> { private static class Node <E> { final E item; final AtomicReference<Node<E>> next; public Node(E item, Node<E> next) { this.item = item; this.next = new AtomicReference<Node<E>>(next); } } private final Node<E> dummy = new Node<E>(null, null); private final AtomicReference<Node<E>> head = new AtomicReference<Node<E>>(dummy); private final AtomicReference<Node<E>> tail = new AtomicReference<Node<E>>(dummy); public boolean put(E item) { Node<E> newNode = new Node<E>(item, null); while (true) { Node<E> curTail = tail.get(); Node<E> tailNext = curTail.next.get(); if (curTail == tail.get()) { if (tailNext != null) { tail.compareAndSet(curTail, tailNext); } else { if (curTail.next.compareAndSet(null, newNode)) { tail.compareAndSet(curTail, newNode); return true; } } } } } } |
相关文章推荐
- jdk concurrent collection---ConcurrentLinkedQueue原理分析
- java多线程-专题-聊聊并发(六)ConcurrentLinkedQueue的实现原理分析
- 聊聊并发(六)ConcurrentLinkedQueue的实现原理分析
- ConcurrentLinkedQueue的实现原理分析
- ConcurrentLinkedQueue的实现原理分析
- Java并发编程-并发队列(ConcurrentLinkedQueue)的原理分析
- Java并发编程-并发队列(ConcurrentLinkedQueue)的原理分析
- 聊聊并发(六)——ConcurrentLinkedQueue的实现原理分析
- 聊聊并发(六)ConcurrentLinkedQueue的实现原理分析
- ConcurrentLinkedQueue的实现原理分析
- 聊聊并发(六)ConcurrentLinkedQueue的实现原理分析
- 聊聊并发(六)——ConcurrentLinkedQueue的实现原理分析
- 聊聊并发(六)ConcurrentLinkedQueue的实现原理分析
- 聊聊并发(6)ConcurrentLinkedQueue的实现原理分析
- ConcurrentLinkedQueue的实现原理分析
- ConcurrentLinkedQueue的实现原理分析
- 聊聊并发(六)——ConcurrentLinkedQueue的实现原理分析
- ConcurrentLinkedQueue的实现原理和源码分析
- 【JUC】JDK1.8源码分析之ConcurrentLinkedQueue(五)
- ConcurrentLinkedQueue非阻塞队列实现原理分析