什么是AQS?
AQS(AbstractQueuedSynchronizer)是一个抽象队列同步器,位于juc.locks包下。abstract说明这是一个抽象类,通常抽象类已经帮我们完成了通用的功能,只需我们实现一些个性化方法即可,模板模式小套路。queued说明依赖FIFO队列,队列的实现方式是一个双向链表。synchronize说明是一个同步组件,可以用来完成多线程访问共享资源同步。
AQS原理?
AQS为每一个临界资源设置一个资源锁,需要访问临界资源的线程必须先获取资源锁,如果获取到了资源锁,便可以在线程中操作临界资源。如果没有获取到资源锁,则入队等待,等待上一个资源锁释放时,重新获取资源锁。许多同步类的实现内部都依赖于AQS,如ReentrantLock、CountDownLatch。
队列节点
节点记录了获取资源锁失败的线程、前驱节点、后继节点以及等待状态,多个线程都没有获取到资源锁时,会同时追加至队列尾部,AQS提供了基于CAS设置尾结点的方法:compareAndSetTail。首节点是获取资源锁成功的节点,首节点释放锁时会唤醒后继节点。
资源状态state
AQS维护了一个volatile int变量,用来标识当前状态,获取资源锁就是根据状态进行判断,基本操作就三个。
protected final int getState() { return state;}protected final void setState(int newState) { state = newState;}protected final boolean compareAndSetState(int expect, int update) { return unsafe.compareAndSwapInt(this,stateOffset,expect,update);}
资源共享方式
AQS支持共享式(share)和独占式(exclusive),AQS只是同步组件,具体的获取释放都由实现组件完成。如ReentrantLock就是独占式,只能有一个线程获取临界资源;CountDownLatch就是共享式,多个线程可以依次获取门闩;当然AQS也支持读共享,写独占,如ReentrantReadWriteLock,读取时共享,写时独占。
总结
基于AQS我们可以实现自己的同步器,也可以参见ReentrantLock等组件的源代码。AQS已经为我们实现好获取资源锁失败入队、唤醒出队等操作,实现组件只需要完成根据状态获取锁、释放锁即可。