1、AQS介绍
AQS的全称是AbstractQueuedSynchronizer,抽象队列同步器。这个类在java.util.concurrent.locks包下面。
AQS就是一个抽象类,主要用来构建锁和同步器。
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer
implements java.io.Serializable {
}
AQS为构建锁和同步器提供了一些通用功能的实现,因此,使用AQS能简单且高效地构建出应用广泛的大量的同步器,比如:ReentrantLock,Semaphore,其他的如:ReentrantReadWriteLock、SynchronousQueue等皆是基于AQS的。
2、AQS原理
AQS核心思想是:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是基于CLH锁实现的。
CLH锁是对自旋锁的一种改进,是一个虚拟的双向队列加粗样式(虚拟的双向队列即不存在队列实例,仅存在结点的关联关系),暂时获取不到锁的线程将被加入到该队列中。AQS将每条请求共享资源的线程封装成一个CLH队列锁的一个结点(Node)来实现锁的分配。在CLH队列锁种,一个节点表示一个线程,它保存着线程的引用(thread)、当前节点在队列中的状态(waitStatus)、前驱节点(pre)、后继节点(next)。
CHL队列锁结构如下图所示:
AQS(AbstractQueuedSynchronizer)的核心原理图:
AQS使用int成员变量state表示同步状态,通过内置的线程等待队列来完成获取资源线程的排队工作。
state变量由volatile修饰,用于展示当前临界资源的获锁情况。
// 共享变量,使用volatile修饰保证线程可见性
private volatile int state;
另外,状态信息state可以通过protected类型的getState()、setState()和compareAndSetState()进行操作。并且,这几个方法都是final修饰的,在子类中无法被重写。
//返回同步状态的当前值
protected final int getState() {
return state;
}
// 设置同步状态的值
protected final void setState(int newState) {
state = newState;
}
//原子地(CAS操作)将同步状态值设置为给定值update如果当前同步状态的值等于expect(期望值)
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
以ReentrantLock为例,state初始值为0,表示值为0,表示未锁定状态。A线程lock()时,会调用tryAcquire()独占该锁并将state+1。此后,其他线程再tryAcquire()时就会失败,直到A线程unlock()到state=0(即释放锁)为止,其他线程才有机会获取该锁。
当然,释放锁之前,A线程自己是可以重复获取此锁的(state会累加),这就是可重入的概念。但要注意,获取多少次就要释放多少次,这样才能保证state是能回到零态的。
再以CountDownLatch为例,任务分为N个子线程去执行,state也初始化为N(注意N要与线程个数一致)。这N个子线程是并行执行的,每个子线程执行完成后countDown()一次,state会CAS(compare and swap)减1。等到所有子线程都执行完后(即state=0),会unpark()主调用线程,然后主调用线程就会从await()函数返回,继续后续动作。
标签:AQS,队列,共享资源,int,state,详解,线程 From: https://blog.51cto.com/u_11315052/6964989