AQS源码解析(一)

今天笔者带大家深入刨析AQS源码的每个方法!!!

方法一:

 protected final boolean compareAndSetState(int expect, int update) {        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);    }

方法解读:如果当前状态值等于预期值,则自动将同步状态设置为给定的更新值。此操作具有 volatile 读写的内存语义。

参数值:参数expect是期望值,参数update是期望值。

返回值:如果成功,返回true。返回false表示实际值不等于预期值。

方法二:

     private Node enq(final Node node) {
        for (;;) {
            Node t = tail;//新建一个节点,使其等于尾部节点
            if (t == null) { // 当当前双向链表未进行初始化,先进行初始化
                if (compareAndSetHead(new Node()))//底层用C++写的,CAS进行设置该节点
                    tail = head;//让tail字段重新赋值为 head 字段,等待队列的头部
            } else {//已经初始化过的,进行插入队列链表操作
                node.prev = t;//节点的前驱设置为当前队列的尾部节点
                if (compareAndSetTail(t, node)) {//底层用C++实现,将该节点插入队列中的 t节点后面
                    t.next = node;//前驱节点指向当前节点
                    return t;
                }
            }
        }
    }

方法解读:将节点插入队列,必要时进行初始化。

参数值:参数node 表示要插入的节点 

返回值:返回节点的前驱

方法三:

    private Node addWaiter(Node mode) {        //Thread.currentThread()返回对当前正在执行的线程对象的引用。    //然后根据当前线程和传入的模式创建对应的节点        Node node = new Node(Thread.currentThread(), mode);        // 试试enq的快速路径;失败时备份到完整的enq        Node pred = tail;//新建一个节点,使其等于尾部节点        if (pred != null) {//尾节点不为空时,尾插入方式建立队列            node.prev = pred;            if (compareAndSetTail(pred, node)) {//CAS操作队列尾部                pred.next = node;                return node;            }        }        enq(node);        return node;    }

方法解读:为当前线程和给定模式创建和排队节点。

参数值:参数 mode 传入Node.EXCLUSIVE 为独占,Node.SHARED 为共享 返回值:返回新节点

ps: pre:链接到当前节点线程依赖于检查 waitStatus 的前驱节点。在入队期间分配,并且仅在出队时清空(为了 GC)。此外,在取消前任后,我们会在找到未取消的前任时进行短路,这将始终存在,因为头节点永远不会被取消:节点仅在成功获取后才成为头。被取消的线程永远不会成功获取,线程只会取消自己,不会取消任何其他节点。

方法四:

    private void setHead(Node node) {        head = node;        node.thread = null;        node.prev = null;    }

方法解读:将队列头设置为节点,从而出队。仅由获取方法调用。为了 GC 和抑制不必要的信号和遍历,还清空未使用的字段。

参数值:参数node 表示节点

方法五:
 


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) {//节点为空或等待状态值大于 0 
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)//则从尾部向后遍历以找到实际未取消的继任者(阻塞状态)。
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
        //使给定线程的许可证可用(如果它尚不可用)。如果线程在 {@code park} 上被阻塞,那么它将解除阻塞。
        //否则,它对 {@code park} 的下一次调用保证不会阻塞。如果给定线程尚未启动,则不保证此操作有任何效果。
            LockSupport.unpark(s.thread);
    }

方法解读:唤醒节点的后继者(如果存在)。 

参数值:参数 node 表示节点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值