作用
参与 共享锁 acquireShared() 和 独占锁 acquire() 的抢锁逻辑, 具体的抢锁逻辑不作实现,只对第一次抢锁未抢到锁线程做处理,第一次抢锁就抢到的线程就不需要遇到AQS了
方法、属性:
AQS属性: head 头结点 已经入队的节点只有前置节点是头节点的情况下才有机会抢锁 tail 尾结点 入队就从这里入 Node属性: pre 前置节点, next 后置节点 waitStatus 状态 0代表已经入队的第一个线程持有锁 1代表下一个线程取消了排队 -1代表可以下一个线程可以抢锁了 -2代表下一个线程正在中断,等待唤醒 -3代表抢的是共享锁,后面的线程抢共享锁的线程都可以得到锁 exclusive 是否独占模式 AQS方法: acquire():未入队的线程抢锁使用这个方法 请求锁,如果未请求成功且以独占模式入队成功则当前线程先中断 acquireQueued():已经入队的线程抢锁使用这个方法 addWaiter(): 描述: 先尝试用CAS进行快速入队,失败则调用enq()方法入队 enq(): 描述 for循环+CAS 入队
独占锁的获取和释放
方法名 | 描述 |
---|---|
acquire() | 请求获取锁,如果未获取成功 &&以独占模式入队成功且前置节点不是头节点 则中断当前线程 |
tryAcquire(arg) | 尝试请求锁,该方法在AQS中不做实现 |
acquireQueued(Node,arg) | 已经入队的线程使用for循环+CAS操作尝试调用tryAcquire()请求锁:当入队后发现前置节点是头节点则尝试请求锁,如果请求成功则出队,如果失败则使用shouldParkAfterFailedAcquire(pred,node)判断是否需要中断当前线程,如果不需要则在循环中继续尝试获取锁 |
shouldParkAfterFailedAcquire(pred,node) | 如果前置节点的waitStatus是SIGNAL则表示当前线程需要中断,或者前置节点被取消了(取消状态是1)就向前查找还在排队的节点,这个时候当前线程还有机会再尝试获取锁 |
addWaiter(mode) | 先尝试使用CAS进行快速入队,失败则调用enq()进行入队 |
enq(node) | 使用for循环加CAS操作进行入队 |
release(arg) | 释放锁:调用tryRelease尝试释放锁,如果释放成功了则判断有没有线程在排队,如果有则使用LockSupport.unpark(Thread)唤醒队列中第一个线程 |
tryRelease(arg) | 尝试释放锁,该方法在AQS中不作实现 |
总结:
对于线程来说最重要的是 获取锁,中断,唤醒,释放锁获取锁:线程入队前会尝试请求一次锁 入队后会检查当前线程的前置节点是不是head节点,如果是且waitStatus是SIGNAL,则尝试获取锁, 中断:线程在未抢到锁的时候中断(废话) 唤醒:(只有未抢到锁的线程且已经入队的线程)线程在队列中的第一个,且持有锁的线程释放了锁 释放锁:已经抢到锁的线程调用release()方法就释放了 节点入队:第一次抢锁未抢到锁就会入队 节点出队:第一次没抢到锁,后来 抢到锁了或者取消抢锁了就会出队