多线程(6)-Compare-and-swap

本文介绍了Java中利用原子类实现线程安全的操作,并深入探讨了底层CPU的CAS指令及其在非阻塞算法中的应用。此外,还讨论了CAS存在的问题如ABA问题及解决方案。

1、java原子类

在java.util.concurrent.atomic下有一些原子操作类,例如:

java.util.concurrent.atomic.AtomicBoolean;

java.util.concurrent.atomic.AtomicInteger;

java.util.concurrent.atomic.AtomicIntegerArray;

java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

有一些类似的方法,比如:

  • AtomicBoolean有 public final boolean compareAndSet(boolean expect, boolean update) ;

  • AtomicInteger有 public final boolean compareAndSet(int expect, int update) ;

等等,基本上都有这么一个compareAndSet方法。

compareAndSet主要做了三件事

  • 比较expect是否与当前数据相等
  • 如果相等,把当前数据更新为update
  • 最重要的是,这两步是原子操作,在多线程是安全的
  • 在很多场景中使用这些原子操作,可以设计一些线程安全操作,例如 使用AtomicBoolean优雅初始化资源

2、CPU CAS指令

通过查看AtomicBoolean的源代码发现,调用了Unsafe JNI代码:

package java.util.concurrent.atomic;
import sun.misc.Unsafe;

public class AtomicBoolean implements java.io.Serializable {
    
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    
    public final boolean compareAndSet(boolean expect, boolean update) {
        int e = expect ? 1 : 0;
        int u = update ? 1 : 0;
        return unsafe.compareAndSwapInt(this, valueOffset, e, u);
    }
    ...
}    
  • 而unsafe.compareAndSwapInt(this, valueOffset, e, u),这段代码本质则是调用了CPU的CAS底层指令,see here
  • 通过CAS指令,在加上一些非阻塞算法,就可以写出多线程安全的乐观锁。关于非阻塞算法

3、CAS一些问题

CAS虽然很高效的解决原子操作,但是CAS仍然存在一些问题。ABA问题,循环时间长开销大。

1.ABA问题。
  • 因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新。
  • 但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。
  • ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A。
  • 从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。关于ABA问题参考文档
2. 循环时间长开销大。
  • 如果CAS如果长时间不成功,会给CPU带来非常大的执行开销。
  • 如果JVM能支持处理器提供的pause指令那么效率会有一定的提升,pause指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。

引用

转载于:https://my.oschina.net/haoran100/blog/716215

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值