AQS与CAS概念
前言
一、什么是AQS?
AQS是java.util.concurrent.locks包下的一个抽象类
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
private static final long serialVersionUID = 7373984972572414691L;
/**
* Creates a new {@code AbstractQueuedSynchronizer} instance
* with initial synchronization state of zero.
*/
protected AbstractQueuedSynchronizer() { }
几乎常用的juc下的组件都是实现了AQS。例如Lock,countDownLatch,Semaphore这些都用了AQS。AQS内部使用int的state变量来标记锁的占用情况,0表示没有人抢占锁,1表示锁被抢占了。
关于state的几个要点:
- 使用volatile修饰,保证多线程间的可见性。
- getState()、setState()、compareAndSetState()使用final修饰,限制子类不能对其重写
- compareAndSetState()采用乐观锁思想的CAS算法,保证原子性操作。
当多个线程修改state时AQS使用了CAS来确保操作的原子性,没有抢到锁的线程会被丢到设计好的FIFO队列(双向链表)里,等待这个链表的头部去唤醒下一个线程去抢锁
此外AQS还提供了两种锁机制
排他锁
使用tryAcquire(int)方法获取锁,使用tryRelease(int)方法释放锁,资源一次只能被一个线程占有。Lock中的ReentrantLock重入锁就用到了AQS的排他锁
共享锁
使用acquireShared(int arg)获取锁、使用releaseShared(int arg)释放锁,资源可以被多个线程获得,CountDownLatch,Semaphore使用了共享锁
二、什么是CAS?
CAS叫做CompareAndSwap,比较并交换,主要是通过处理器的指令来保证操作的原子性,它包含三个操作数:
1、变量内存地址,V表示
2、旧的预期值,A表示
3、准备设置的新值,B表示
当执行CAS指令时,只有当V等于A时,才会用B去更新V的值,否则就不会执行更新操作。
但是CAS不能避免ABA问题,java中提供了一个AtomicStampedReference来解决这个问题,他加入了预期标志和更新后标志两个字段,更新时不光检查值还检查标准来避免ABA问题