并发编程实战学习笔记(十一)-原子变量与非阻塞同步机制

原子变量在非阻塞算法的应用

实现基础

用底层的原子机器指令(例如比例并交换指令)代替锁来确保数据在并发访问中的一致性。

缺点

非阻塞算法在设计与实现上比阻塞算法都要复杂得多。

优点

  • 在可伸缩性和活跃性上拥有巨大的优势。由于非阻塞算法可以使多个线程竞争相同的数据时不会发生阻塞,因此它能在粒度更细的层次上进行协调,并且极大地减少调度开销。
  • 不存在死锁和其它活跃性问题。
  • 即使原子变量没有用于非阻塞算法的开发,它们也可以用做一种“更好的volatile类型变量”。

原子变量与锁适用的不同并发场景

  • 在中低程序的竞争、锁占用时间不长的情况下,原子变量能提供更高的可伸缩性

基于原子变量而实现的非阻塞算法本质是一个乐观锁,认为在大部分时间不会有竞争或者只有较小的竞争,所以用较短时间的自旋这个小代价来代替因为竞争锁而阻塞,出现的线程调度成本。

  • 而在高强度的竞争下,锁能够更有效的地避免竞争。

高强度的竞争下,非阻塞算法会出现大量在自旋的的线程,由此导致的CPU资源耗用会大于因线程挂起而导致的上下文切换。这个时候,不如直接使用锁机制来得高效。

非阻塞算法举例

非阻塞算法通常比基于锁的算法更为复杂。创建非阻塞算法的关键在于,找出如何将原子修改的范围缩小到单个变量上,同时还要维护数据的一致性。

非阻塞的栈

public class ConcurrentStack<E> {

    AtomicReference<Node<E>> head = new AtomicReference<Node<E>>();

    public void push(E item) {
        Node<E> newHead = new Node<E>(item);
        Node<E> oldHead;
        do {
            oldHead = head.get();
            newHead.next = oldHead;
        } while (!head.compareAndSet(oldHead, newHead));
    }

    public E pop() {
        Node<E> oldHead;
        Node<E> newHead;
        do {
            oldHead = head.get();
            if (oldHead == null)
                return null;
            newHead = oldHead.next;
        //如果更新的时候其它线程已经先于本线程更新成功了,则会循环进行此操作,直到它先于其它线程更新成功
        //通过这种方式,就实现了将原子修改的范围缩小到单个变量上,同时也能保持数据一致性。
        } while (!head.compareAndSet(oldHead,newHead));
        return oldHead.item;
    }

    static class Node<E> {
        final E item;
        Node<E> next;
        public Node(E item) { this.item = item; }
    }

}

非阻塞链表

参考Michael-Scott提出的非阻塞链接队列算法。(Michael and Scott ,1996)
这里只简单过一下,核心的要点,上述栈的实现已经有所体现。

双重检查加锁(DCL)

问题分析

当在没有同步的情况下读取一个共享对象时,可能发生的最糟糕事情只是看到一个失效值(在这种情况下只是一个空值),此时DCL方法将通过在持有锁的情况下再次尝试来避免这种风险。然而,实际情况远比这种情况糟糕——线程可能看到引用的当前值,但对象的状态却是失效的,这意味着可以看到对象处于无效或错误的状态。

获得锁的线程并未将对象完全初使化完成,比如部分变量初使化代码尚未执行,但对应的static引用已经指向了引用的地址,另一个线程此时来访问就会认为引用不是null,从而继续往下走逻辑出现未知的风险。

解决办法

jdk5.0以后,把变量声明为volatile类型,那么就能启用DCL,并且这种方式对性能的影响很小。
虽然也有人用临时变量解决了这个问题,但相对volatile方法来说,要复杂的多,所以建议选择上述方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值