并发编程实战学习笔记(十一)-原子变量与非阻塞同步机制
2017-04-05 17:44
996 查看
原子变量在非阻塞算法的应用
实现基础
用底层的原子机器指令(例如比例并交换指令)代替锁来确保数据在并发访问中的一致性。缺点
非阻塞算法在设计与实现上比阻塞算法都要复杂得多。优点
在可伸缩性和活跃性上拥有巨大的优势。由于非阻塞算法可以使多个线程竞争相同的数据时不会发生阻塞,因此它能在粒度更细的层次上进行协调,并且极大地减少调度开销。不存在死锁和其它活跃性问题。
即使原子变量没有用于非阻塞算法的开发,它们也可以用做一种“更好的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方法来说,要复杂的多,所以建议选择上述方法。
相关文章推荐
- Java并发读书学习笔记(十一)——原子变量与非阻塞同步机制
- JAVA 并发编程实践 - 原子变量与非阻塞同步机制 笔记
- 并发编程11.原子变量与非阻塞同步机制
- 读书笔记:Java并发实战第15章 原子变量与非阻塞同步机制
- 并发编程实战学习笔记(十)-构建自定义的同步工具
- Java 并发编程实战学习笔记
- 并发编程实战学习笔记(六)——线程池的使用
- Java 并发编程实战学习笔记——串行任务转并行任务
- Java 并发编程实战学习笔记——寻找可强化的并行性
- Java 并发编程实战学习笔记——CountDownLatch的使用
- 并发编程实战学习笔记(八)——性能与可伸缩性
- 多线程并发编程之原子变量与非阻塞同步机制
- 并发编程实战学习笔记(五)——取消与关闭
- 并发编程实战学习笔记(七)——避免活跃性问题
- 并发编程实战学习笔记(二)——对象的共享
- linux网络编程学习笔记之五 -----并发机制与线程�
- 并发编程实战学习笔记(九)-显式锁
- 并发编程实战学习笔记(三)——基础构建模块
- 并发编程 21—— 原子变量和非阻塞同步机制
- linux网络编程学习笔记之五 -----并发机制与线程池