AQS源码解析

//加锁从 先看一下 acquire方法开始

    private transient volatile Node head;  //头节点  获取锁的线程节点
 
    private transient volatile Node tail;  //尾节点
Node  内部类
       //共享
        static final Node SHARED = new Node();
       
        //独占
        static final Node EXCLUSIVE = null;
 
        //取消状态
        static final int CANCELLED =  1;
        //释放资源后唤醒的后继节点
        static final int SIGNAL    = -1;
        //等待condition唤醒
        static final int CONDITION = -2;
        //工作于共享锁状态,需要向后传播,
        //比如根据资源是否剩余,唤醒后继节点
        static final int PROPAGATE = -3;
 
        //等待状态,1,0,-1,-2,-3。
        volatile int waitStatus;
 
        //前驱节点
        volatile Node prev;
 
        //后继节点
        volatile Node next;
 
        //等待锁的线程
        volatile Thread thread;
 
        //等待条件的下一个节点,ConditonObject中用到
        Node nextWaiter;

    public final void acquire(int arg) {
    //查看是否能获取锁,如果获取锁直接结束 ,未获取锁,调用  addWaiter 方法,Node为独占锁
        if (!tryAcquire(arg) &&
        //调用addWaiter 加入等待队列,并且加入acquireQueued 中 那么让我们看一下addWaiter()方法
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

//1. 第一个方法 默认由子类实现
    protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

	//加入队列中
    private Node addWaiter(Node mode) {
    	//给当前线程创建一个Node
        Node node = new Node(Thread.currentThread(), mode);
        // 将tail Node  赋值给前驱节点 ,
        Node pred = tail;
        //如果pred不为null 
        if (pred != null) {
        	//将node的上一个节点设置为 pred,也就是tail
            node.prev = pred;
            	//cas设置  期待值 pred  更新值 node  快速入队
            if (compareAndSetTail(pred, node)) {
            	//如果cas成功,那么  tail (pred) 的下一个节点设置为 node
                pred.next = node;
                return node;
            }
        }
        //如果 pred是null  或者设置失败 ,调用enq
        enq(node);
        return node;
    }

	//继续接下来的 enq
    private Node enq(final Node node) {
    //cas 加 自旋
        for (;;) {
          // 尾节点赋值给 t
            Node t = tail;
            //t 如果是 null  尾节点是 null  那么证明队列没有初始化
            if (t == null) { // Must initialize
               //初始化  设置一个虚假的头节点
                if (compareAndSetHead(new Node()))
                	//头节点指向尾节点
                    tail = head;
            } else {
              //t 如果不是null    将 node 的 prev 设置为 tail
                node.prev = t;
                //进行设置尾节点  预估值 t  实际值 node  本来尾节点是 t 现在设置为 node
                if (compareAndSetTail(t, node)) {
                // 当前获取锁的节点的  next  设置为 node
                    t.next = node;
                    return t;
                }
            }
        }
    }
	//继续
    final boolean acquireQueued(final Node node, int arg) {
       //是否失败   默认失败
        boolean failed = true;
        try {
        	//默认未中断
            boolean interrupted = false;
            //cas 加 自旋
            for (;;) {
               // 获取上一个在等待的节点
                final Node p = node.predecessor();
                //如果当前节点的上一个节点 p  如果是头节点, 那么当前节点 node就是老二, 可以尝试获取锁,尝试成功,则当前 节点 node 设置为头节点,  原头节点 p 引用设置为null,help gc
                if (p == head && tryAcquire(arg)) {
                   //设置当前节点为头节点
                    setHead(node);
                    //p.next 设置为null 无指向的引用
                    p.next = null; // help GC
                    //设置为成功
                    failed = false;
                    return interrupted;
                }
                //如果 不是头节点, 或者锁没有获取成功, 调用 是否应该在等待队列 park
                // 线程被唤醒之后,已经执行完 parkAndCheckInterrupt() 方法, 继续执行,因为再 for循环中,所以 继续拿当前界面去尝试,尝试失败,继续park
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
           //如果是失败了, 那么 取消当前节点
            if (failed)
                cancelAcquire(node);
        }
    }

	//开始
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
       //pred 前驱节点  node 当前节点
        int ws = pred.waitStatus;
        //如果是  获取锁的线程 可以唤醒后续线程,那么直接true
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
             //正常 可以安心去睡
            return true;
            //如果前置 pred 取消了
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
               // 前置的前置节点 赋值给  前置节点, 并且赋值给 node 的前置节点, 一直找到 pred.waitStatus 小于等于 0的
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            //前置节点 的 next 设置为当前 节点
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
             //如果是小于 0  设置尾 SIGNAL  需要唤醒后续节点
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

    //在看一下 park    将该线程 等待
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }
`
总结 :  先尝试默认获取锁,获取失败加入等待队列,等待队列中 如果还没有获取, 在等待 释放锁之后唤醒,继续抢占锁,抢占不到,继续睡
  1. 看一下释放锁
    public final boolean release(int arg) {
    	//尝试释放锁, 返回 boolean  释放成功或者失败
        if (tryRelease(arg)) {
        	//释放成功 ,头节点赋值给 h
            Node h = head;
            // head 或者 h 不为null  并且  h的等待状态不为 0 
            if (h != null && h.waitStatus != 0)
            	//可以唤醒其他线程
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

    private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
         //head的 等待状态
        int ws = node.waitStatus;
        //小于 0 
        if (ws < 0)
            //设置为 0
            compareAndSetWaitStatus(node, ws, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
         //获取当前节点的next 节点
        Node s = node.next;
        //如果是 null  或者 状态 大于 0 
        if (s == null || s.waitStatus > 0) {
            // s 赋值为 null
            s = null;
            // 从后向前循环
            for (Node t = tail; t != null && t != node; t = t.prev)
                //获取到 waitStatus 小于等于 0 
                if (t.waitStatus <= 0)
                    //t赋值给 s
                    s = t;
        }
        //s 不等于 null
        if (s != null)
            //唤醒s线程
            LockSupport.unpark(s.thread);
    }

总结 : 根据状态去唤醒下一个线程  如果下一个线程为null  那么从后向前循环 找到一个符合条件的线程唤醒
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值