在缓存领域有一对奇葩,多线程的缓存和单线程的redis,而两者的性能是差不多的,之所以redis能凭借单线程提供强大的性能并且线程安全操作:

一是不存在多线程直接切换的资源开销,

二是大部分的指令都是原子的,原子的指令拥有更高的效率,并且保证线程安全!

在java中的原子操作主要封装在并发包下,以Atomic打头的类中,如下截图:

JAVA面试中常常问到的无锁CAS是什么?

观察这些类发现,其中的原子操作主要依赖于UnSafe包中类似unsafe.compareAndSwapInt这样的算法,取单词首字母,也即是CAS操作,这也是实现无锁操作保证线程安全的基石,乐观锁因为建立在CPU的底层指令原子操作,效率比起同步锁相当高;

CAS:compare,and,swap:顾名思义,就是比较并交换,这属于一种乐观锁思想,悲观锁通常是把共享资源的持有者当做互斥的,由此保证针对共享资源操作的只会是持有锁的程序!

乐观锁之所以称为乐观,就是假设数据在操作之前都是没有被修改过的,如果已经被修改过,则不进行操作,降低了阻塞的可能性!

CAS的思想在sql操作中常常用到,比如未付款status=1,已付款status=2,sql:update set status=2,version=version+1 where id = xx and status =1 and version=${version},即是如果是还未付款的状态则付款,如果已经付过款(status=2),则操作失败;

但是CAS也存在问题:

①,ABA问题,比如上面的sql,如果status是会从1(A)到2(B)再到1(A)的,那么就会存在线程一已经从1->2->1了,而线程二还认为整个数据都没有变过,继续修改数据;

②,性能浪费:CAS的操作依赖于自旋(不断循环到满足条件),如果条件一直不满足,则CPU开销一直存在;

下面以AtomicInteger 为例说下CAS的应用类特性:

JAVA面试中常常问到的无锁CAS是什么?

1,从构造器和get,set方法来看,处理的值需要修饰为内存可见的valatile

JAVA面试中常常问到的无锁CAS是什么?

2,大多数的方法都是使用了unsafe中的compareAndSwap方法,都是native方法,说明是底层封装;

直接看案例,如下截图:

JAVA面试中常常问到的无锁CAS是什么?

案例中的AtomicInteger,如果改成Integer,结果基本都会小于100,说明数据计算错误了!