CAS全程 Compare And Swap,比较并交换,它低层调用的是基于硬件平台的汇编指令,指令叫cmpxchg,低层会判断当前系统是多处理器,如果是则cmpxchg指令会添加lock前缀,如果不是就不加lock前缀,java提供的Unsafe方法就是调用汇编指令封装的。
cas操作过程:
获取内存中的值,然后拿着旧的预期的值和内存中的值作比较,如果比较相等,再用新的值去替换到内存的值,如果内存的值变化了就替换成功,如果没有成功会做自旋重试进行比较。保证每次只有一个线程能够执行。
cas是一种乐观锁,不需要加锁。
乐观锁:
每次获取数据的时候,都不会担心数据被修改,所以每次获取数据的时候都不会进行加锁,但是在更新数据的时候需要判断该数据是否被别人修改过。
如果数据被其他线程修改,则不进行数据更新,如果数据没有被其他线程修改,则进行数据更新。
由于数据没有进行加锁,期间该数据可以被其他线程进行读写操作 (乐观锁的一种实现方式CAS实现的)
cas缺点:
1、cas操作在并发较高的情况下,会导致多线程同时反复尝试修改变量不成功,做循环重试操作,会导致cpu开销很大。
2、cas操作只能保证一个变量的原子性操作,不能保证整个代码块的原子性。用Synchronize锁活ReentrantLock锁解决。
3、存在ABA问题。线程1准备将变量由A修改成B,但是线程2在之前已经将变量由A修改成C,再由C修改成A,线程1执行cas操作发现变量仍是A,所以线程1也能cas成功。
ABA问题需要用一个版本号解决,每次修改后版本号递增操作,在比较内存中的值和旧的预期的值相等的时候,还需要版本号的比较相等,两个相等才能替换成新的值。
======================================================================
java提供了Unsafe魔法类,封装的cas操作的汇编指令。主要三个方法
unsafe方法还提供能够访问对外内存的方法
Java锁和同步器框架的核心类AbstractQueuedSynchronizer,就是通过调用LockSupport.park()和LockSupport.unpark()实现线程的阻塞和唤醒的,而LockSupport的park、unpark方法实际是调用Unsafe的park、unpark方式来实现。
Atomic类的实现就是用了Unsafe实现的
基本类:AtomicInteger、AtomicLong、AtomicBoolean
引用类型:AtomicReference、AtomicReference的ABA实例
AtomicStampedRerence、AtomicMarkableReference; 数组类型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray 属性原子修改器(Updater):AtomicIntegerFieldUpdater、 AtomicLongFieldUpdater、AtomicReferenceFieldUpdater