15-原子变量与非阻塞同步机制

锁的劣势:

1,线程等待锁,不能做其他事情(如果占用锁的线程阻塞,则等待队列一直等待),优先级反转

2,同步成本比较高

3,当前线程获取锁失败,则将当前线程挂起,活跃性问题,cpu利用率低

 

volitile比锁更轻量的同步机制

优点:没有上下文切换和线程调度,可见性保证

缺点:不能构建原子的复合操作

 

硬件对并发的支持

1,比较并交换指令 CAS:

  三个参数(内存位置,比较的值,新值)

  如果值被其他线程修改,CAS能检测到这个错误,返回失败但不会挂起(相比锁而言)

  减少了活跃性风险

  存在活锁问题

  缺点:

  需要调用者处理竞争问题:重试,回退,放弃(锁能自动处理竞争问题,挂起(阻塞)等待线程)

  CAS的性能跟CPU处理器数有关,需要处理处理器之间的同步

  

2,JVM对对CAS的支持

  编译为对应的CAS指令,如果硬件平台不支持CAS,则自旋锁(spin)

 

原子变量类:

  比锁的粒度更细(竞争范围缩小到单个变量上),量级更轻

  快速路径

  泛化的volatile变量,支持原子的 有条件的 读-改-写操作

  更高的可伸缩性

  4组共12个原子变量类:

    标量类:AtomicInteger AtomicLong AtomicBoolean AtomicReference(支持算数运算:AtomicInteger AtomicLong)

      其他基本类型(char,byte)可以通过类型转换为int,浮点类型(floatToIntBits,floatToLongBits)来使用标量类

      标量类没有扩展基本类型包装类,因为基本类型包装类是不可修改final的

    更新器类:AtomicIntegerFieldUpdater AtomicLongFieldUpdater AtomicReferenceFieldUpdater

    数组类:AtomicReferenceArray AtomicIntegerArray AtomicLongArray

      数组元素可以实现原子更新,给数组元素提供了volatile类型的访问语意,volatile数组仅对数组引用本身有volatile语意

    复合变量类:AtomicMarkableReference, AtomicStampedReference(AtomicReference的功能增强版,解决CAS的ABA问题)

1,better version of volatile

  竞态条件

  破坏数据一致性

2,性能比较: 锁 vs 原子变量

  可伸缩性差异

  

  超高度竞争条件下,原子变量调用者需要处理竞争的管理(重试),重试在激烈的竞争环境下导致了更多的竞争

  但总的来说,原子变量的性能将超过锁,锁会挂起线程,降低cpu使用率和共享内存总线上的同步通信量

  可伸缩性 原子变量 > 锁

  中低端强度竞争 原子变量 > 锁

  高强度竞争 原子变量 < 锁

  ThreadLocal是无锁的

 

非阻塞算法

1,非阻塞的栈

  关键:如何将原子修改的范围缩小到单个变量上,同时还要维护数据一致性

  栈的结构:每个元素仅指向一个元素,每个元素只被一个元素引用

 

  compareAndSet既提供了原子性,又提供了可见性

   竞争失败时必须重试

2,非阻塞的链表

  队列的结构:头结点和尾节点,头指针和尾指针,有两个指针会指向尾节点,最后一个元素的next指针和尾指针,插入元素时需要保证这两个指针操作的原子性操作

 

3,原子的域更新器

  更新目标类实例中的指定域,原子性更新,原子性保证更弱一点(因为只能保证使用其他使用原子域更新器的线程的原子性)

  volatile域

 

4,ABA问题

  CAS引起的一个问题:三个线程CAS一个值A,t1:A->B,t2:B->A,t3看到A值可能没有变,认为A没有被更新,实际上是被更新过

 解决方案:

  增加版本号,每更新一次,增加一次版本号  

     支持在两个变量上执行原子的条件更新 AtomicMarkableReference, AtomicStampedReference

 

posted on 2017-12-02 12:17  Vindia  阅读(231)  评论(0)    收藏  举报

导航