1.是什么
aqs即AbstractQueueSynchronizer。是并发大神doug lea的杰作。是java中一系列锁实现的基础,
比如常用的可重入锁ReentrantLock,CountDownLatch,Semaphore。
2.实现
状态state+CLH队列
根据当前state是否为0判断是否可以获取锁,队列是一个双向队列,其中每个结点有排队线程,结点的信号等信息。
以非公平锁为了,我们在外界调用lock方法的时候,源码是这样实现的
1):CAS尝试获取锁,获取成功则可以执行同步代码
2):CAS获取失败,则调用acquire方法,acquire方法实际上就是AQS的模板方法
3):acquire首先会调用子类的tryAcquire方法(又回到了ReentrantLock中)
4):tryAcquire方法实际上会判断当前的state是否等于0,等于0说明没有线程持有锁,则又尝试CAS直接获取锁
5):如果CAS获取成功,则可以执行同步代码
6):如果CAS获取失败,那判断当前线程是否就持有锁,如果是持有的锁,那更新state的值,获取得到锁(这里其实就是处理可重入的逻辑)
7):CAS失败&&非重入的情况,则回到acquire方法执行acquireQueued(addWaiter(Node.EXCUSIVE))「入队列」的操作,这里如果head和tail都为空,会先初始化一个空的node,作为哨兵结点,所以队列头节点始终是一个空值的node(信号量有值)
哨兵结点的作用?不用频繁判空,保持代码一致性。
8):将节点入队列之后,会判断「前驱节点」是不是头节点,如果是头结点又会用CAS尝试获取锁
9):如果是「前驱节点」是头节点并获取得到锁,则把当前节点设置为头结点,并且将前驱节点置空(实际上就是原有的头节点已经释放锁了)
10):没获取得到锁,则判断前驱节点的状态是否为SIGNAL,如果不是,则找到合法的前驱节点,并使用CAS将状态设置为SIGNAL
11):最后调用LockSupport.park(属于native本地方法)将当前线程挂起