jdk concurrent collection---ConcurrentLinkedQueue原理分析

先来回顾之前提到过的ConcurrentHashMap,它是一个以Concurrent开头的并发集合类,其原理是通过增加锁和细化锁的粒度来提高并发度。
    另一个值得一提的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;
            }
        }
    }
    }
}
}

 

转自 http://blog.sina.com.cn/s/blog_58adc9e701000az6.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值