AQS思路实现细节理解
成员变量
1.state 用来判断资源是否被释放的标记位 volatile保证了线程之间的可见性
思考为什么不使用boolean 更小的空间 而且有二义性 -> 独占和共享 state需要表示 共享线程的数量
2.头结点 尾节点 FIFO 双向链表
Node 内部类

还有一个ConditionObject内部类
我们主要关注如何State 和先进先出 的队列来管理多线程的同步状态
考虑两种业务场景
1.获取锁 获取不到返回false
2.获取锁 愿意等待

AQS 给上层调用开放空间 上层必须Override这个方法 来自由编写业务逻辑 比如说Reentrantlock的sync的实现
使用到了 ** 的设计模式
tryAcquire 非公平

公平的实现

如果是选择等待获取锁的场景 可以直接使用AQS 中等待锁的acquire实现 而不用自己去实现复杂的排队处理

继承类不可重写
tryAcquire失败 调用 addWaiter
将当前线程封装成node 加入等待队列 返回当前节点

尾节点为空或者cas失败 进入完整的入队方法 对当前队列进行初始化 并且自旋的方式将当前节点插入 直到入队成功
疑惑: 为什么不直接使用完整的入队 方法 而是 先尝试入队? 完全入队多了一个判空操作 可能是重复的判空操作会影响性能
一开始我陷入为主的认为 遵循了生产消费模型 让消费者去获取节点 然后让节点中封装的线程去拿锁
看看作者的想法:
acquireQueued 方法 和release方法 对线程进行挂起和响应 以此实现先入先出
    @ReservedStackAccess
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
        //
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
          // 头结点其实是哨兵节点  能拿锁的是第二个节点
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
          //判断当前节点是否应该挂起   其实不挂起一直自旋也行  但是如果大量线程自旋 会导致性能问题  所以应该把没有轮到它出队的线程挂起合适的时间唤醒
          // 等待状态的线程被中断会抛出中断异常  运行状态会改变一个中断状态值不影响运行   interrupt isinterrupted interrupted 
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())    //第二个与条件 执行真正的挂起操作 LockSupport.park()
                    interrupted = true;
            }
        } finally {
       //return 之前failed才可能是false  抛出异常后 cancleAcquire waitState 设置成CANCLE 以及一些清理操作
            if (failed)
                cancelAcquire(node);
        }
    }
  

什么时候挂起?
当前的节点之前除了head还有其他节点 并且前一个 节点也是siginal 当前挂起 保证只有一个线程在自旋
线程在什么时候被唤醒? 应该是一个线程 释放锁的时候
 

传进来的head 该方法是为了唤醒Head 后面的node 使得其自旋地获取锁 head的status应该设置为0这个默认值
    private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }
从尾结点开始搜索 找到除head外最靠前的 并且status<=0的节点 对其进行unpark
被唤醒就会继续执行acquireQueue方法 尝试获取锁
为什么从后往前找?
Thread的interrupt操作 ?
                    
                
                
            
        
浙公网安备 33010602011771号