1. CAS原理
中文名叫比较交换---Compare And Swap
CAS(V,E,N)
V表示要更新的值;
E表示预期值;
N表示新值。
比较原则:当V和E相等时,才把N赋值给V;如果V和E不相等时,放弃当前修改;重新读取,再次尝试修改。
1.1 如何保证原子性
基于硬件的汇编指令实现原子性,使用CPU指令保证原子性;
// Unsafe 后门类,用于直接操作内存中的数据
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
/**
* CAS实现
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
* 使用自旋的方式保证线程安全
*/
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return prev;
}
1.2 CAS的缺点
循环时间太长
有些类限制了自旋的次数
只能保证一个共享变量的原子操作
ABA问题
如果一个值原来是A,变成了B,然后又变成了A,那么在CAS检查的时候会发现没有改变,但是实质上它已经发生了改变,这就是所谓的ABA问题。
使用类AtomicStampedReference来解决ABA问题。
如果当前引用 == 预期值,并且当前标志值 == 预期标志值,则就将当前引用和当前标志值赋值为更新值。
/**
* CAS实现
*
* @param expectedReference 引用的预期值
* @param newReference 引用的新值
* @param expectedStamp 标志的预期值
* @param newStamp 标志的新值
*/
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}
2. AQS原理
AQS----AbstractQueuedSynchronizer的缩写
子类定义为非公共内部帮助器类(私有的内部类继承AQS);写锁的时候的一个帮助器,提供获取锁和是释放锁的功能模板。
acquire(int arg) 以独占模式获取对象,忽略中断。
acquireShared(int arg) 以共享模式获取对象,忽略中断。
tryAcquire(arg) 试图在独占模式下获取对象状态。
tryAcquireShared(int arg) 试图在共享模式下获取对象状态
release(int arg) 以独占模式释放对象。
releaseShared(int arg) 以共享模式释放对象