深入理解 Java 中的 CAS

2020-04-08  本文已影响0人  张贤同学

Java 中的synchronized是一种悲观锁,悲观锁始终假设会发生并发冲突,因此会阻止一切可能违反数据完整性的操作。而 CAS 是一种乐观锁
CAS 全称是 Compare and Swap。乐观锁假设不会发生并发冲突,因此只在提交的时候检查是否违反数据完整性,如果提交失败则会进行重试。

CAS 支持原子更新操作,适用于计数器,序列发生器等场景。CAS 操作失败时由开发者决定是继续尝试,还是执行别的操作。

CAS 的思想:
CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。

更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。

public class CASCase {
    public volatile int value;

    public void add(){
        value++;
    }
}

使用javap查看编译后的add()方法中的value++的字节码如下:


2: getfield      #2                  // Field value:I
5: iconst_1
6: iadd
7: putfield      #2                  // Field value:I

可以看到value++被分成了三步,虽然value变量使用了volatile修饰,对value++操作禁止了指令重排序,但是value++不是原子性操作,在多线程并发下还是会产生线程安全问题。一种解决的办法是给add()方法加上synchronized关键字,但是synchronized属于悲观锁,是否能够进一步提升性能呢?其实还可以使用AtomicInteger来满足我们的要求

public class CASCase {
    public AtomicInteger value;

    public void add(){
        value.getAndIncrement();
    }
}

getAndIncrement()方法底层调用的是Unsafe类的compareAndSetInt方法,用到的就是 CAS 的思想。

CAS 多数情况下对开发者来说是透明的。J.U.C 的 atomic 包提供了常用了原子性数据类型以及引用、
数组等相关原子类型和更新操作工具,是很多线程安全程序的首选。Unsafe 类虽然提供 CAS 服务,但是因为能够操纵任意内存地址读写而有隐患。在 Java9 之后,可以使用 Variable Handle API 来替代 Unsafe。

CAS 虽然很高效,但是也有缺点:

上一篇 下一篇

猜你喜欢

热点阅读