CAS
- CAS,Compare and Swap即比较并交换。
- java.util.concurrent包借助CAS实现了区别于synchronized同步锁的一种乐观锁。
- 乐观锁就是每次去取数据的时候都乐观的认为数据不会被修改,所以不会上锁,但是在更新的时候会判断一下在此期间数据有没有更新。
- CAS有3个操作数:内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
- CAS的关键点在于,系统在硬件层面保证了比较并交换操作的原子性,处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子操作。
- Unsafe类中有多线程的一些方法:如CAS和内存屏障,线程挂起恢复等。可以直接操作内存,指针,跳过构造方法创建类等。所以不安全
优点
CAS由于是在硬件层面保证的原子性,不会锁住当前线程,它的效率是很高的。
缺点
- 并发越高,失败的次数会越多,CAS如果长时间不成功,会极大的增加CPU的开销。因此CAS不适合竞争十分频繁的场景。理论上如此,但是其上限很高
- ABA问题。
- CAS必然有ABA问题,因为CAS比较的是值,即是结果,而不是过程。
- 需要结合使用分析。版本号解决的思路。
- 只能保证一个共享变量的原子操作。
- AtomicReference类来保证引用对象的原子性,即对象引用/内存地址的原子性,可以把多个变量放在一个final对象里来进行CAS操作。
Atomic介绍
- Atomic类可以保证多线程环境下,当某个线程在执行atomic的方法时,不会被其他线程打断,
- 而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个线程执行。
- Atomic类在软件层面上是非阻塞的,它的原子性其实是在硬件层面上借助相关的指令来保证的,因此性能高于自己加锁。
Atomic分类
- AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference // CAS不防止ABA
- AtomicIntegerArray,AtomicLongArray ,AtomicReferenceArray //针对数组中的元素进行原子操作
- AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater //Field是针对不是自己创建的类,构造原子类,实现原子操作
- AtomicMarkableReference,AtomicStampedReference //版本号,防止ABA
AtomicInteger
常用方法
- get() 直接返回值
- getAndAdd(int) 增加指定的数据,返回变化前的数据
- getAndDecrement() 减少1,返回减少前的数据
- getAndIncrement() 增加1,返回增加前的数据
- getAndSet(int) 设置指定的数据,返回设置前的数据
- addAndGet(int) 增加指定的数据后返回增加后的数据
- decrementAndGet() 减少1,返回减少后的值
- incrementAndGet() 增加1,返回增加后的值
- lazySet(int) 仅仅当get时才会set
- compareAndSet(int, int) 尝试新增后对比,若增加成功则返回true否则返回false
使用了自旋CAS,实现了原子操作。