zoukankan      html  css  js  c++  java
  • 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);
        }
    }
  • 相关阅读:
    Hadoop安装教程_单机/伪分布式配置_Hadoop2.6.0/Ubuntu14.04
    练oj时的小技巧(大多都在oj记录里,这是被忘记的部分)
    HDU 3032 (SG打表找规律)
    SG 大法(Sprague-Grundy函数)
    基于Linux的MySQL基本操作
    java.sql.SQLException: Unable to load authentication plugin ‘caching_sha2_password‘.解决方法
    手把手教你安装和配置MYSQL数据库
    理解Python闭包,这应该是最好的例子
    SQL基础
    MySQL令人咋舌的隐式转换
  • 原文地址:https://www.cnblogs.com/yaowen/p/11355117.html
Copyright © 2011-2022 走看看