AQS4源码

@SuppressWarnings("restriction")
public abstract class AbstractQueuedSynchronizer1 extends AbstractOwnableSynchronizer1 implements java.io.Serializable {
    private static final long serialVersionUID = 7373984972572414691L;
    protected AbstractQueuedSynchronizer1() {}
    protected final int getState() {
        return state;
    }
    protected final void setState(int newState) {
        state = newState;
    }
    static final long spinForTimeoutThreshold = 1000L;

    //写成员变量时候用到cas,读的时候不用cas,有可能读到之后改变了,所以写的时候就会失败。
    //写成员变量都要CAS,除非是要强制修改,覆盖别人的修改。
    
    private Node enq(final Node node) {//修改尾节点失败
        for (;;) {
            Node t = tail;
            if (t == null) {//如果尾指针为null,则头指针也一定为null,表示等待队列未初始化,就CAS初始化队列。  
                if (compareAndSetHead(new Node()))//相当于加锁,因为不会重新获取头结点。
                    tail = head;//初始化头尾节点为空节点,
            } else {//如果尾指针非null,则队列已初始化,就CAS尝试在尾节点后插入新的节点node。
                node.prev = t;
                if (compareAndSetTail(t, node)) {//修改尾节点为新节点(成员变量变了,局部变量没变),失败了node.prev=t也无效。
                    t.next = node;//for的死循环,所以不相当于加锁,因为重新获取了尾节点,里面可以多线程都进来,但是不影响。
                    return t;
                }
            }
        }
    }

    //mode:Node.EXCLUSIVE独占, Node.SHARED共享的。
    private Node addWaiter(Node mode) {
        // 构造节点,mode有两种:EXCLUSIVE(独占)和SHARED(共享)
        Node node = new Node(Thread.currentThread(), mode);//多个线程在排队,一个线程附在一个Node节点,
        Node pred = tail;
        if (pred != null) {//尾节点不为null,其实被enq(node)重复了。
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {//修改共享变量cas, 成员变量变了,局部变量没变。失败node.prev=pred无效。
                pred.next = node;//里面可以多线程都进来,但是不影响。因为pred=tail=新的节点node,重新获取了尾节点。
                return node;//返回新尾节点
            }
        }
        enq(node);//修改尾节点失败。自旋的方式继续加入等待队列。
        return node;//返回新尾节点
    }

    //将队列的头设置为节点,从而使其出列。仅由Acquire方法调用。为了GC,还可以空出未使用的字段,并抑制不必要的信号和遍历。
    private void setHead(Node node) {
        head = node;
        node.thread = null;
        node.prev = null;
    }

    //node可能是head节点可能是失效节点。
    private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)//-1就设置为0,异常节点这里是1。    头结点要么是0要么是-1。头结点设置为0.
            compareAndSetWaitStatus(node, ws, 0);

        /*head下一个节点,从头结点开始一个个的找后继,直到把队列找完。
        next节点是正常的就找next,next不是正常的,就不能再找next,因为next.next有可能是自己。
        就tail往前找,从tail往前找prev一定能够吧所有正常节点找到(还会找到不正常的节点)。
        如果找到的这个节点status<=0,然后唤醒,但是这个节点异常了只是状态没有修改过来,
        那么唤醒的这个假正常节点就不会去获取锁,而是帮着正常节点做 ,做完退出。
        */
        
        Node s = node.next;//node=head,head.next不一定是初始节点,可能被改过指向曾经正常的一个节点,这个节点现在正常与否未知。
        //下一个节点s被取消,node还没来得及重新设置新的正常后继节点。队列还没有处于稳定状态。
        //第一个节点被取消,就从后往前找下一个状态正常节点。也相当于是head后面第一个status正常节点。
        
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev) //右边的正常节点。
                if (t.waitStatus <= 0)//  0/-1都唤醒
                    s = t;
        }
        if (s != null)//s可能=head,head.thread=null就什么都不做。
            LockSupport.unpark(s.thread);
    }

    private void doReleaseShared() {// 读锁释放(共享锁),这个方法只会唤醒一个节点
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {//-1, 如果头节点状态为SIGNAL,说明要唤醒下一个节点,并且设置0成功就唤醒下一个,
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))//设置为0成功(没有异常)就去unparkSuccessor,设置为0失败就跳过unparkSuccessor再次从head开始,
                        continue;  
                    
                    unparkSuccessor(h);//唤醒下一个节点
                    
                //等于0  并且  设置-3失败,就跳过,  把头节点的状态改为PROPAGATE成功才会跳到下面的if
                } else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue; // 
            }
            if (h == head) // head变化了,继续唤醒head,
                break;//头结点变了,head后面节点自行出队了,
        }
    }

    private void setHeadAndPropagate(Node node, int propagate) {
        Node h = head;  
        setHead(node);
        // 如果旧的头节点或新的头节点为空或者其等待状态小于0(表示状态为SIGNAL/PROPAGATE)
        if (propagate > 0 || h == null || h.waitStatus < 0 || (h = head) == null || h.waitStatus < 0) {
            Node s = node.next;//node下一个节点,需要传播
            if (s == null || s.isShared()) // 如果下一个节点为空,或者是需要获取读锁的节点
                doReleaseShared();//唤醒head下一个节点
            //一个节点A获取了读锁后,会唤醒下一个读节点B,这时候B也会获取读锁,然后B继续唤醒C,依次往复,
            //也就是说这里的节点是一个唤醒一个这样的形式,而不是一个节点获取了读锁后一次性唤醒后面所有的读节点。
        }
    }

    /* 所看到的所有成员变量都在工作内存里面,局部变量更在工作内存里面。 */
    
    //有可能是0变到1,也有可能是-1变到1, 
    private void cancelAcquire(Node node) {
        if (node == null)
            return;
        node.thread = null;//异常节点,thread先清空,
        
        /*失效节点:不断改变自己的前驱         在改变status   最后改变next*/
        
        Node pred = node.prev;//node就是头结点,pred就是null,
        while (pred.waitStatus > 0)//找到新的-1/0,跳过已经取消的节点。 
            node.prev = pred = pred.prev;//断开node.prev。node.prev只有节点自己线程修改不用cas,
        //while出来时候pred=0/-1,while之后pred可能变为1。  0/-1节点在任何时候都有可能变为1,每次判断都只是瞬间的值。
        
        /*pred = pred.prev;不是改变属性
        node.prev = pred是改变属性*/

        Node predNext = pred.next;//此时pred可能是0/-1节点也可能是1节点.

        /* 节点异常了只能通过status和thread看得出来。否则外界不知道异常了。别人也是通过status来看这个节点是不是异常了,所以有延时。 */
        
        node.waitStatus = Node.CANCELLED;//强制覆盖,不用cas,以这个为主。

        //修改队列。去掉的节点是尾节点就要修改,尾节点就不需要prev.next了。
        if (node == tail && compareAndSetTail(node, pred)) {//死循环的cas会重来,一次cas失败了就放弃让别人去做,优先级低于直接赋值。
            //修改tail为pred,修改失败:不是尾节点了,加进来了新的节点。
            //pred.next!=predNext就是有节点加进来了,并且pred.next=新的节点,就不置位null。
            compareAndSetNext(pred, predNext, null);//tail的next置位null,GC
            
        } else {//不是尾节点,或者是尾节点但是加进来了新的节点,
            int ws;
            if (pred != head  //node前面是head,就不要去设置后继关系,而是唤醒,
                    &&  
                    /* 再次判断pred的状态是正常=0/-1
                     有可能这时候prev=head,并且有可能head=0已经出队了,pred.thread = null就要唤醒node后面*/
                    
                    /*prev不是头结点并且异常了,如果不管了,如果后面正常节点阻塞了,并且前面没有正常节点
                    那么head=0 unlock出队失败时候,队列里面的就全阻塞了,就永远不能出队。*/
                    
                    ( (ws = pred.waitStatus) == Node.SIGNAL|| ( 
                            ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL) )   ) 
                    && pred.thread != null 
                ) 
            {
                //pred不是头节点,并且,pred正常 
                //有可能这时候prev=head,但是head=-1,可以正常唤醒。
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)//next节点也可能是取消了。
                    //pred.next没有被修改。next不可能为null,因为线程退出了节点可能还在,
                    compareAndSetNext(pred, predNext, next);//把node也跳过,失败不重来,因为别的正常-1节点也会修改,让正常节点。
                
            } else {//node.prev=head,ndoe异常,
                //node不一定是紧挨着head的节点,正常节点在node后面并且在第一个栅栏里面, 
                //如果这里不唤醒,只是依靠unlock唤醒,但是unlock在head=0时候是不会唤醒的什么都不做的,unlock在这种情况不负责唤醒线程获取锁,
                //那么就该第一个栅栏里面的正常节点去获取锁,防止正常节点阻塞了,这里就要去唤醒,否则unlock出队失败就永远不能唤醒。
                
                //或者,node不是第一个节点但是prev状态值=1了,或者,node不是第一个节点prev状态值=0/-1但是prev的thread=null了
                unparkSuccessor(node);//唤醒node这个异常节点的后面节点
            }

            node.next = node; // help GC。断开node.next
        }
    }

    //前驱节点是-1就阻塞。前驱节点是0就是初始化设置为-1,并且清理失效的节点。直到找到-1为止。
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        //第一次进来,pred.waitStatus=默认值0,然后设置=-1,parkAndCheckInterrupt()失败会再次进来,直接返回true,表示应该阻塞。
        //第一次进来不阻塞,第二次进来阻塞。
        int ws = pred.waitStatus;//0 1 -1 -2 -3。
        
        //前驱=-1,当前节点node应该阻塞。SIGNAL表示释放后需要唤醒后继节点。
        if (ws == Node.SIGNAL)//这一行pred=-1,下一行pred可能会变为1,
            return true;
        
        
        //其余返回false,当前节点不应该阻塞。
        //清理失效的节点,并把新的前驱节点设置为-1。跳过现在是1的,并且是1之后不会变回-1。
        if (ws > 0) {//waitStatus = 1,清理CACELLED节点。
            do {
                node.prev = pred = pred.prev;//pred往前进一个,
            } while (pred.waitStatus > 0);//<=0作为边界
            pred.next = node;//回指肯定成功。 直接赋值覆盖cas赋值。
         
        } else {//0或者-3 -2,是1不会变为-1。就是前驱后继关系。
            //ws此时=0/-3/-2就说明没有取消就设置为-1,ws=1说明取消了,不能设置为-1。
            
            /* 再次判断pred的状态为正常=0 */
            
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);//设置新的前驱waitStatus=-1,有可能失败。被自己改为了1就以1为主,这边失败算了。
            //有可能马上被设置为1,即使cas了也不保证cas下一行状态没改变,只是保证获取ws到改变期间没有变化,这一行之后变化了不管。
        }
        
        /*找前驱节点:不断改变自己的前驱       在改变找到节点的next  最后修改找到节点的status*/
        
        return false;
    }

    static void selfInterrupt() {
        //线程被打上中断标记。但是线程正常执行,只有判断是否中断然后return线程才会停止。否则跟没有中断是一样的。
        Thread.currentThread().interrupt();
    }

    private final boolean parkAndCheckInterrupt() throws InterruptedException   {//阻塞并看阻塞是否成功
        Thread t = Thread.currentThread();
        if(t.getName().equals("")  ) {
            throw new InterruptedException();
        }
        LockSupport.park(this);//阻塞,this=ReentrantLock对象。直到被唤醒或者中断。
        return Thread.interrupted();//唤醒时候,中断唤醒返回true,interrupted=true,获取到锁(设置了成员属性的值)之后还是会中断。并复位,
    }

    //返回true当前线程就阻塞(就没有获取锁),返回false就不阻塞(就获取了锁)。一次只能一个线程执行(exclusiveOwnerThread=的线程执行),其余阻塞
    // 节点加进去之后,就死循环(死循环也是在最前面才获取锁,否则死循环或者阻塞),
    final boolean acquireQueued(final Node node, int arg) throws InterruptedException   {
        boolean failed = true;
        try {
            boolean interrupted = false;
            //旋转1次,旋转2次,旋转3次,或者多次阻塞,compareAndSetWaitStatus(pred, ws, Node.SIGNAL)有可能一直失败,多次在于这里。
            for (;;) {
                final Node p = node.predecessor(); 
                //是最前面的节点(节点从前到后依次获取锁),并且获取锁成功,就不阻塞,这个节点退出链表,更新链表,Lock方法返回。
                
                if (p == head && tryAcquire(arg)) {//否则死循环(自旋出队)。获取锁的线程只有一个,所以这里是加锁。tryAcquire方法在Write锁里面会重写
                    //setHead()加锁了不用CAS(只有修改成员变量cas否则都是线程的局部内部变量)。
                    //head=node,node.thread=null,node.prev=null。thread就是调用这个函数的线程设置为null(已经获取了锁就移除这个节点)。
                    
                    //head指向正在运行的线程的节点,就是不在排队中的节点的线程。 如果不在队列的线程获取了锁,head不变继续指向。
                    //如果队列中的线程获取了锁,head就指向新的获取锁的线程的节点。
                    setHead(node);//node变成空节点并升级为头节点。    status=0/-1没变。
                    p.next = null; // help GC,node变为头结点,head节点gc,
//                    if(Thread.currentThread().getName().equals("1号窗口")  ) {
//                        throw new InterruptedException();
//                    }
                    failed = false;//不走cancelAcquire(node),
//                    if(Thread.currentThread().getName().equals("1号窗口")  ) {
//                        throw new InterruptedException();
//                    }
                    return interrupted;//已经获取了锁,就不用中断了,lock方法返回void,不用阻塞了。先执行finally再return。
                }
                
                //不是最前面的节点,或者 是最前面的节点但是获取锁失败。判断当前线程是否需要阻塞。
                
                //shouldParkAfterFailedAcquire()判断当前线程是否需要阻塞 (通过前驱节点判断)
                //parkAndCheckInterrupt()阻塞当前线程 ,阻塞失败继续死循环。
                if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
                    interrupted = true;//如果状态为true说明发生过中断,会补发一次中断,中断唤醒的线程应该去中断而不是继续执行,即调用interrupt()方法
            }
        } finally {//不异常也走这里然后return,
            if (failed)//node成为了头节点异常,线程退出,head节点还在,
                //抛出任何异常,则取消任务。这里不catch,外层函数要catch,否则异常一直在。
                cancelAcquire(node);
        }
    }

    //这个线程能够响应中断,即中断线程的等待状态
    private void doAcquireInterruptibly(int arg) throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);//添加一个独占的节点,
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
                    throw new InterruptedException();//线程中断唤醒抛出异常
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

    private boolean doAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;//获取截止时间点
        final Node node = addWaiter(Node.EXCLUSIVE);//节点模式是独占的
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                nanosTimeout = deadline - System.nanoTime();//截止时间过了没有
                if (nanosTimeout <= 0L)// 超过时间,依然获取不到,则返回false;否则返回true
                    return false;
                //不会一直阻塞等待唤醒,只会阻塞一定时间,
                if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);//阻塞剩余的时间
                if (Thread.interrupted())// 等待过程中,可以被中断,中断就抛异常,不像别的中断后继续运行,只是设置中断标记,然后我们自己去处理。
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    //ReadLock获取锁走这个方法,AQS排队,
    private void doAcquireShared(int arg) throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);//ReadLock节点是共享模式,nextWaiter是一个空节点(共享模式是null【ReentrantLock和WriteLock】)
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {//自旋
                final Node p = node.predecessor();
                if (p == head) {//是第一个节点。获取锁
                    int r = tryAcquireShared(arg);//尝试获取锁,返回-1获取锁失败,返回1获取锁成功。
                    if (r >= 0) {//获取成功, 
                        // 头节点后移并传播。传播即唤醒后面连续的读节点
                        setHeadAndPropagate(node, r);//node变为头结点
                        p.next = null; // help p GC
                        if (interrupted)//中断唤醒在获取的锁
                            selfInterrupt();//设置中断标记
                        failed = false;
                        return;
                    }
                }    //设置前面-1然后阻塞,
                    if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
                        interrupted = true;
            }
        } finally {//不异常也走这里
            if (failed)
                cancelAcquire(node);//异常设置自己=1,并帮助清理AQS的异常节点,建立后驱或者唤醒后面节点
        }
    }

    private void doAcquireSharedInterruptibly(int arg) throws InterruptedException {//Semaphore排队,多线程
        final Node node = addWaiter(Node.SHARED);//共享节点,Semaphore可以多线程进入,所以跟读锁是一样的,
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);//获取许可,返回减1后的许可
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);//r=0,说明没有许可,就不会去唤醒下一个节点
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

    /**
    以共享定时模式获取
     */
    private boolean doAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return true;
                    }
                }
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

    protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

    protected boolean tryRelease(int arg) {
        throw new UnsupportedOperationException();
    }

    protected int tryAcquireShared(int arg) {
        throw new UnsupportedOperationException();
    }

    protected boolean tryReleaseShared(int arg) {
        throw new UnsupportedOperationException();
    }

    protected boolean isHeldExclusively() {
        throw new UnsupportedOperationException();
    }
    
    //ReentrantLock和WriteLock获取锁,走这个方法,tryAcquire在ReentrantReadWrite里面有重写
    public final void acquire(int arg) throws InterruptedException   {//tryAcquire会先去获取锁,获取成功返回true否则false。
        //addWaiter()穿建一个独占的节点添加到尾节点去。 
        //如果获取失败,则向等待队列中添加一个独占模式的节点,并通过acquireQueued()阻塞的等待该节点被调用(即当前线程被唤醒)。
        //如果是因为被中断而唤醒的,则复现中断信号。
        //acquireQueued()检查node的前继节点是否是头节点。如果是,则尝试获取锁;如果不是,或是但获取所失败,都会尝试阻塞等待。
        //addWaiter时候线程异常了,不会吧head置为1.
        if (!tryAcquire(arg) && 
                //返回是否中断,如果返回中断,则调用当前线程的interrupt()方法
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            
            selfInterrupt();//interrupted = true当前线程中断执行。重放acquireQueued里面的中断。
    }

    //跟acquire差不多
    public final void acquireInterruptibly(int arg) throws InterruptedException {
        if (Thread.interrupted())//线程中断标志为1
            throw new InterruptedException();//线程中断抛出异常
        if (!tryAcquire(arg))//获取一次锁
            doAcquireInterruptibly(arg);
    }

    public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout);
    }

    public final boolean release(int arg) {//只有一个线程访问
        if (tryRelease(arg)) {//true就表示OwnerThread=null了state=0了,减少state和OwnerThread。
            //tryRelease()返回true表示已完全释放,可唤醒所有阻塞线程;否则没有完全释放,不需要唤醒。这个线程要再次unlock才去唤醒队列的节点。
            Node h = head;
            
            //头结点只能是0/-1不可能是1。头结点由第一个入队节点创建,第一个入队节点线程异常了也只会设置第一个节点=1,不会影响到头结点,不会设置到头结点=1。
            //头结点看成一直是正常节点,
            if (h != null && h.waitStatus != 0) 
                unparkSuccessor(h);//head.waitStatus=-1才进来,唤醒head的后继
            
            //h=null,头结点都还没有建立,队列也还没有建立。
            /*或者h!=null&&head.waitStatus==0,
             最近的正常节点不一定是紧挨着的节点,最近的正常节点中间可能还有异常节点。
             head.waitStatus变成-1是由head后面的最近正常节点设置的(不一定是紧挨着的节点),说明曾经有一个正常节点执行完了3步,这个正常节点是否还正常未知。
             head.waitStatus==0说明head后面都异常了,或者后面第一个正常节点(不一定是紧挨着的节点)还没有自旋到这一步,还没被阻塞 。说明没有曾经一个正常节点完成了3步,把他设置成-1。
             如果head后面的正常节点都阻塞了(仅仅只需要看最近的正常节点),必然会设置head=-1,并且是由最近正常节点设置的。 
            */
            //lock时候head.waitStatus==0不出对,说明都不做,head不改变。唤醒时候head不变,只有获取到锁之后,head变化。
            return true;
        }
        return false;//unlock就不会去唤醒等待的第一个节点
    }

    //ReadLock获取锁走这个方法,tryAcquireShared在ReentrantReadWrite里面,doAcquireShared在AQS里面,
    public final void acquireShared(int arg) throws InterruptedException {
        if (tryAcquireShared(arg) < 0)//获取共享锁,读锁,获取失败,排队。
            doAcquireShared(arg);//排队
    }

    public final void acquireSharedInterruptibly(int arg) throws InterruptedException {//Semaphore获取一个许可
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)//Semaphore获取一个许可,有许可只是没有获取到,就死循环获取许可,
            doAcquireSharedInterruptibly(arg);//只有在许可没了才去排队,Semaphore排队
    }

    public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquireShared(arg) >= 0 || doAcquireSharedNanos(arg, nanosTimeout);
    }

    public final boolean releaseShared(int arg) {// 读锁释放(共享锁),多线程访问
        if (tryReleaseShared(arg)) {//释放锁,释放之后state=0返回true。读锁全部释放完了,才会去唤醒AQS
            doReleaseShared();//唤醒head下一个
            return true;
        }
        return false;
    }

    public final boolean hasQueuedThreads() {
        return head != tail;
    }

    public final boolean hasContended() {
        return head != null;
    }

    public final Thread getFirstQueuedThread() {
        //前面是快速失败
        return (head == tail) ? null : fullGetFirstQueuedThread();
    }

    private Thread fullGetFirstQueuedThread() {
        /*
        第一个节点通常是head.next,尝试获取其线程字段,确保一致的读取:
         如果线程字段为空或s.prev不再是head,我们试了2次。
         */
        Node h, s;
        Thread st;
        if (((h = head) != null && (s = h.next) != null && s.prev == head && (st = s.thread) != null)
                || ((h = head) != null && (s = h.next) != null && s.prev == head && (st = s.thread) != null))
            return st;

        Node t = tail;
        Thread firstThread = null;
        while (t != null && t != head) {
            Thread tt = t.thread;
            if (tt != null)
                firstThread = tt;
            t = t.prev;
        }
        return firstThread;
    }

    public final boolean isQueued(Thread thread) {
        if (thread == null)
            throw new NullPointerException();
        for (Node p = tail; p != null; p = p.prev)
            if (p.thread == thread)
                return true;
        return false;
    }

    //第一个节点线程部位null并且不是共享的读锁
    protected final boolean apparentlyFirstQueuedIsExclusive() {
        Node h, s;
        return (h = head) != null && (s = h.next) != null && !s.isShared() && s.thread != null;
    }
    
    //h=t有可能是指向同一个,有可能都是null。h!=t有可能指向不同的,有可能head!=null但tail=null。
    //注意;一个节点变成null只能通过GC,有人指向就不会GC变成null,没有主动置为null的语句。中间节点的next不可能指向一个null,next指向的节点有人指向不会被GC,也没有主动设置为null的语句,
    /*队列的状态:1(false,获取锁)head tail都是null            2(true,排队)head!=null tail=null,head的next和prev都=null,有人在初始化队列,  
                 3(false,获取锁,此时有线程正在入队,不准确)head=tail!=null,但是next和prev都是null      4(false,获取锁)有第一个节点是当前线程,head tail都!=null,head.next=tail tail.next=null  
                   5(true,排队)有第一个节点不是当前线程,head tail都!=null,head.next=tail tail.next=null  */
    //h!=t && h.next=null,那么tail就等于null还没有初始化,head!=null。
    public final boolean hasQueuedPredecessors() {
        Node t = tail; 
        Node h = head;
        Node s;
        /*
         公平原则:没人占用锁时候,要不要去获取锁。有线程在队列里面,说明那些是获取锁失败的才去排队。没有线程获取锁,线程是第一个节点获取锁,第一个节点不是当前线程排队。
         当然这个不一定准确:有可能别的线程已经开始排队了,只是没有完全加入到队列,另一个线程过来还是可以立马获取锁。但是单单只看第一个节点存不存在,也不准确。
         */                                              
                           
        //返回true排队,true&&(true||)。true&&(false||true)。有第一个节点不是当前线程,或者 ,有别人在初始化队列,.
        //返回fasle获取锁:   false。true&&(false||false):对裂空没有线程,有第一个节点是当前线程
        return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());
        //h!=t&&h.next=null 或者  h!=t&&h.next.thread!=currentThread()  返回true排队。否则获取锁。
        // 有人在初始化   或者    有第一个节点不是当前线程。
    }

    public final int getQueueLength() {//不是线程安全
        int n = 0;
        for (Node p = tail; p != null; p = p.prev) {
            if (p.thread != null)
                ++n;
        }
        return n;
    }

    public final Collection<Thread> getQueuedThreads() {//不是线程安全
        ArrayList<Thread> list = new ArrayList<Thread>();
        for (Node p = tail; p != null; p = p.prev) {
            Thread t = p.thread;
            if (t != null)
                list.add(t);
        }
        return list;
    }

    public final Collection<Thread> getExclusiveQueuedThreads() {//不是线程安全
        ArrayList<Thread> list = new ArrayList<Thread>();
        for (Node p = tail; p != null; p = p.prev) {
            if (!p.isShared()) {
                Thread t = p.thread;
                if (t != null)
                    list.add(t);
            }
        }
        return list;
    }

    public final Collection<Thread> getSharedQueuedThreads() {//不是线程安全
        ArrayList<Thread> list = new ArrayList<Thread>();
        for (Node p = tail; p != null; p = p.prev) {
            if (p.isShared()) {
                Thread t = p.thread;
                if (t != null)
                    list.add(t);
            }
        }
        return list;
    }

    public String toString() {
        int s = getState();
        String q = hasQueuedThreads() ? "non" : "";
        return super.toString() + "[State = " + s + ", " + q + "empty queue]";
    }

    final boolean isOnSyncQueue(Node node) {
        //=-2就是不在AQS的同步队列,在condition的等待队列, prev=null肯定不在AQS,便说明节点还在Condition队列中
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
        // 说明当前Node的状态不是CONDITION,同时它既有prev节点也有next节点,那么说明它在AQS队列里   
        if (node.next != null)  
            return true;
        return findNodeFromTail(node);//node在不在AQS同步队列中
    }

    private boolean findNodeFromTail(Node node) {//node在不在AQS同步队列中
        Node t = tail;//从tail往前可以找到所有AQS的节点
        for (;;) {
            if (t == node)
                return true;
            if (t == null)
                return false;
            t = t.prev;
        }
    }

    final boolean transferForSignal(Node node) {
        //唤醒从-2变成0,condition加到AQS時候狀態是0,唤醒失败就是=1,await里面唤醒AQS时候异常了,设置为1了,就去唤醒下一个,
        //此时他不移到AQS继续放到condition队列,不是-2就表示已经加入到队列去了,
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;
        Node p = enq(node);//把节点加到AQS队列,直接把condition節點全部拿過來,屬性值=-2不變,返回AQS尾节点就是前面一个节点
        int ws = p.waitStatus;
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))//AQS前面节点异常了,或者设置-1失败了,就唤醒自己,防止自己在AQS上的时候不能够唤醒去获取锁。
            LockSupport.unpark(node.thread);//node移到AQS唤醒并且return true,
        //ws<=0&&compareAndSetWaitStatus(p,ws,-1)成功,node移到AQS不唤醒并且return true。
        return true;
    }

    //中断唤醒时候=-2没有开始加入AQS返回-1,=0开始加入AQS返回1,
    final boolean transferAfterCancelledWait(Node node) {
        //中断唤醒,但是!=-2,说明还没有signal(有可能signal了只是还没有改变状态),還沒有加入隊列,幫助加入AQS隊列,
        if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { 
            enq(node);
            return true;
        }
        //不是-2已经设置为0了,已经signal了改变状态=0了,只是没有执行到加入到队列这行,等待signal线程加入到AQS队列,
        while (!isOnSyncQueue(node))//不在AQS队列就让步。等著加到AQS去
            Thread.yield();
        return false;
    }

    final int fullyRelease(Node node) {
        boolean failed = true;
        try {
            int savedState = getState();//Sync的state
            //unlock调用release(1),这里全部释放。
            if (release(savedState)) {//通过head唤醒AQS队列中下一个节点。state变成0。release成功返回true没有唤醒成功返回false
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
            if (failed)//release(savedState)异常了,就设置condition队列中的自己=1,
                node.waitStatus = Node.CANCELLED;//出现异常=1
        }
    }

    public final boolean owns(ConditionObject condition) {
        return condition.isOwnedBy(this);
    }

    public final boolean hasWaiters(ConditionObject condition) {//不是线程安全
        if (!owns(condition))
            throw new IllegalArgumentException("Not owner");
        return condition.hasWaiters();
    }

    public final int getWaitQueueLength(ConditionObject condition) {//不是线程安全
        if (!owns(condition))
            throw new IllegalArgumentException("Not owner");
        return condition.getWaitQueueLength();
    }

    public final Collection<Thread> getWaitingThreads(ConditionObject condition) {//不是线程安全
        if (!owns(condition))
            throw new IllegalArgumentException("Not owner");
        return condition.getWaitingThreads();
    }

    //内部类,可以使用外部类的方法和属性
    public class ConditionObject implements Condition, java.io.Serializable {
        private static final long serialVersionUID = 1173984872572414699L;
        private transient Node firstWaiter;//Condition的等待队列的头尾。AQS有一个队列,Condition有一个队列。
        private transient Node lastWaiter;

        public ConditionObject() {}

        private Node addConditionWaiter() {
            //Condition对队列的操作没考虑并发,因为对应的操作都是在线程获得锁之后才进行的
            
            Node t = lastWaiter;
            //尾节点!=-2就清除,Condition里面的节点状态只能是0和-2,否则就是无效节点
            if (t != null && t.waitStatus != Node.CONDITION) {//=1,
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
            //创建新的节点放到Condition队列,移除AQS节点。
            //AQS节点prev!=null,next只有最后一个=null。
            //Condition节点,prev=next=null,nextWaiter只有最有一个=null。 
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }

        //
        private void doSignal(Node first) {
            do {
                if ((firstWaiter = first.nextWaiter) == null)//只有一个,并且移除了,就都是null。
                    lastWaiter = null;
                first.nextWaiter = null;//把nextWaiter置为了null,
                //把condition的第一個移到AQS去,不一定喚醒線程,
            } while (!transferForSignal(first) && (first = firstWaiter) != null);
        }

        //condition隊列移到AQS隊列,
        private void doSignalAll(Node first) {
            lastWaiter = firstWaiter = null;
            do {
                Node next = first.nextWaiter;
                first.nextWaiter = null;
                transferForSignal(first);
                first = next;
            } while (first != null);
        }

        //从第一个到最后一个,清除无效!=-2的节点。单向链表。
        private void unlinkCancelledWaiters() {
            Node t = firstWaiter;
            Node trail = null;
            while (t != null) {
                Node next = t.nextWaiter;
                if (t.waitStatus != Node.CONDITION) {
                    t.nextWaiter = null;
                    if (trail == null)
                        firstWaiter = next;
                    else
                        trail.nextWaiter = next;
                    if (next == null)
                        lastWaiter = trail;
                } else
                    trail = t;
                t = next;
            }
        }

        //唤醒Condition队列第一个非CANCELLED节点。
        public final void signal() {
            if (!isHeldExclusively())//获得锁的线程是不是当前线程,当前线程没有获取锁,
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
        }

        //condition全部移到AQS
        public final void signalAll() {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignalAll(first);
        }

        //当前线程进入等待状态直到被通知,在此过程中对中断信号不敏感,不支持中断当前线程
        public final void awaitUninterruptibly() {
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            boolean interrupted = false;
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                if (Thread.interrupted())//和await()区别是线程中断不会退出循环
                    interrupted = true;
            }
            try {   //恢复之前的锁状态并相应中断
                if (acquireQueued(node, savedState) || interrupted)
                    selfInterrupt();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        private static final int REINTERRUPT = 1;//线程在等待过程中发生了中断,但不需要抛出异常
        private static final int THROW_IE = -1;//线程在等待过程中发生了中断,且需要抛出异常

        //没有中断返回0,中断返回-1说明中断时候没有调用signal抛出异常,返回1说明中断时候调用了signal设置自己中断标记。
        private int checkInterruptWhileWaiting(Node node) {
            return Thread.interrupted() ? (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0;
        }

        private void reportInterruptAfterWait(int interruptMode) throws InterruptedException {
            if (interruptMode == THROW_IE)
                throw new InterruptedException();
            else if (interruptMode == REINTERRUPT)
                selfInterrupt();
        }

        //当前获取lock的线程进入到等待队列。  只有获取锁的线程才进来,单线程的。
        public final void await() throws InterruptedException {
            if (Thread.interrupted()) throw new InterruptedException();
            //将当前线程包装成Node(只要了線程屬性,其餘屬性沒要),尾插入到Condition等待队列中,
            Node node = addConditionWaiter();
            
            //释放锁,设置state=0,清空owenerThread,唤醒AQS,
            //记录之前的state,唤醒后需要恢复状态,后续unlock()也要unlock这么多次不然将报错。
            //线程从lock开始到这一行,都是要获取锁的,所以是线程安全的,。 
            int savedState = fullyRelease(node); 
            //await开始一直到上面一行,都是线程安全的,下面就不线程安全了。
            
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {//当前节点到AQS队列之后就退出while循环,唤醒时候有可能不在AQS队列上就阻塞直到在AQS队列上。
                LockSupport.park(this);//当前线程在condition上阻塞,等著移到AQS,然後在AQS隊列裡面喚醒。喚醒時候已經在AQS隊列裡面了。
                
                /* 如果是中断唤醒,发生时期是任意的。可能在condition里面可能在AQS里面 */
                
                //中断唤醒,不是AQS的head唤醒,有可能还不在AQS队列里面。checkInterruptWhileWaiting会帮助加入队列,
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)//等于0就不是中断唤醒,=-1抛出异常 =1设置中断标记
                    //没有开始加入AQS返回-1,=0开始加入AQS返回1,
                    
                    break;//中断唤醒就跳出while,正常唤醒就继续while看是不是在AQS队列
            }
            //在AQS队列上唤醒,尝试获取AQS的鎖,可能会再次在AQS上阻塞,恢复await前的状态savedState,
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)//-1
                //AQS唤醒了,获取到锁了,
                //后面代码又是线程安全的。
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // 清除ConditioN队列中 != -2 的节点
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);//-1就抛出异常,1就设置自己中断标记。
        }

        public final long awaitNanos(long nanosTimeout) throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();//加入Condition队列
            int savedState = fullyRelease(node);//释放锁
            final long deadline = System.nanoTime() + nanosTimeout;//过期时间点
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                if (nanosTimeout <= 0L) {
                    transferAfterCancelledWait(node);//加入队列
                    break;
                }
                if (nanosTimeout >= spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                //判断线程是否被中断
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
                nanosTimeout = deadline - System.nanoTime();
            }
            //响应中断
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null)
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
            return deadline - System.nanoTime();//返回耗时
        }

        public final boolean awaitUntil(Date deadline) throws InterruptedException {
            long abstime = deadline.getTime();
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            boolean timedout = false;
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                if (System.currentTimeMillis() > abstime) {
                    timedout = transferAfterCancelledWait(node);
                    break;
                }
                LockSupport.parkUntil(this, abstime);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null)
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
            return !timedout;
        }

        public final boolean await(long time, TimeUnit unit) throws InterruptedException {
            long nanosTimeout = unit.toNanos(time);
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            final long deadline = System.nanoTime() + nanosTimeout;
            boolean timedout = false;
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                if (nanosTimeout <= 0L) {
                    timedout = transferAfterCancelledWait(node);
                    break;
                }
                if (nanosTimeout >= spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
                nanosTimeout = deadline - System.nanoTime();
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null)
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
            return !timedout;
        }
        //判断Condition是否属于sync.
        final boolean isOwnedBy(AbstractQueuedSynchronizer1 sync) {
            return sync == AbstractQueuedSynchronizer1.this;
        }

        protected final boolean hasWaiters() {//不是线程安全
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
                if (w.waitStatus == Node.CONDITION)
                    return true;
            }
            return false;
        }

        protected final int getWaitQueueLength() {//不是线程安全
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            int n = 0;
            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
                if (w.waitStatus == Node.CONDITION)
                    ++n;
            }
            return n;
        }

        protected final Collection<Thread> getWaitingThreads() {//不是线程安全
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            ArrayList<Thread> list = new ArrayList<Thread>();
            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
                if (w.waitStatus == Node.CONDITION) {
                    Thread t = w.thread;
                    if (t != null)
                        list.add(t);
                }
            }
            return list;
        }
    }
    
    static final class Node {
        //节点是共享节点
        static final Node SHARED = new Node();
        // 节点是独占节点
        static final Node EXCLUSIVE = null;
        //由于超时或中断,此节点被取消。  
        static final int CANCELLED = 1;
        //-1,唤醒,这个节点成为head结点时候,unlock会去通过head唤醒后继节点
        static final int SIGNAL = -1;
        //表示当前节点在等待condition,即在condition队列中;
        static final int CONDITION = -2;
        //表示releaseShared需要被传播给后续节点(仅在共享模式下使用);
        static final int PROPAGATE = -3;
        volatile int waitStatus;//默认0,
        //前继节点;
        volatile Node prev;
        //后继节点;
        volatile Node next;
        //当前线程。
        volatile Thread thread;

        //condition节点的属性,ReentrantLock时候nextWaiter=null,
        Node nextWaiter;

        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() { // Used to establish initial head or SHARED marker
            this.name = "头结点";
        }
        volatile String name;
        Node(Thread thread, Node mode) { //用于锁
            this.nextWaiter = mode;//独占锁的nextWaiter是模式=Node.EXCLUSIVE=null,
            this.thread = thread;
            this.name = this.thread.getName();
        }

        Node(Thread thread, int waitStatus) { //用于Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
            this.name = this.thread.getName();
        }
        public String toString() {
            return "name:"+this.name+",prev:" + prev.name + ",next:" + next.name;
        }
    }

    //head指向获取锁的线程的节点,仅仅保存next结点的引用。。如果是没有入队的线程获取锁,head不变。head节点是一个哨兵节点 ,头结点不存储Thread,仅
    private transient volatile Node head;

    private transient volatile Node tail;//tail指向链表的最后一个节点

    //如果没有记录重入次数,则第一次释放锁时,会一次性把ownerThread多次重入的锁都释放掉,而此时“锁中的代码”还没有执行完成,造成混乱。
    private volatile int state;//所有者线程已经重复获取该锁的次数,每次加1。
    
    private static Unsafe unsafe;
    private static final long stateOffset;//state
    private static final long headOffset;//head
    private static final long tailOffset;//tail
    private static final long waitStatusOffset;//Node.waitStatus
    private static final long nextOffset;//Node.next

    static {
        try {
            unsafe = java.security.AccessController
                    .doPrivileged(new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
                        public sun.misc.Unsafe run() throws Exception {
                            Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
                            for (java.lang.reflect.Field f : k.getDeclaredFields()) {
                                f.setAccessible(true);
                                Object x = f.get(null);
                                if (k.isInstance(x))
                                    return k.cast(x);
                            }
                            throw new NoSuchFieldError("the Unsafe");
                        }
                    });
            stateOffset = unsafe.objectFieldOffset(AbstractQueuedSynchronizer1.class.getDeclaredField("state"));
            headOffset = unsafe.objectFieldOffset(AbstractQueuedSynchronizer1.class.getDeclaredField("head"));
            tailOffset = unsafe.objectFieldOffset(AbstractQueuedSynchronizer1.class.getDeclaredField("tail"));
            waitStatusOffset = unsafe.objectFieldOffset(Node.class.getDeclaredField("waitStatus"));
            nextOffset = unsafe.objectFieldOffset(Node.class.getDeclaredField("next"));

        } catch (Exception ex) {
            throw new Error(ex);
        }
    }
    
    protected final boolean compareAndSetState(int expect, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
    
    private final boolean compareAndSetHead(Node update) {
        return unsafe.compareAndSwapObject(this, headOffset, null, update);
    }

    private final boolean compareAndSetTail(Node expect, Node update) {
        return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
    }

    private static final boolean compareAndSetWaitStatus(Node node, int expect, int update) {
        return unsafe.compareAndSwapInt(node, waitStatusOffset, expect, update);
    }

    private static final boolean compareAndSetNext(Node node, Node expect, Node update) {
        return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
    }
}

 

转载于:https://www.cnblogs.com/yaowen/p/11355117.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值