Java8 ConditionObject 源码解析

   目录

1、定义

         2、使用

3、await / awaitUninterruptibly

4、await / awaitNanos / awaitUntil

5、signal / signalAll

6、其他方法实现总结


      上一篇《Java8 ReentrantLock 源码解析》中主要讲解了lock和unlock相关方法的实现,本篇讲解ReentrantLock的newCondition方法返回的ConditionObject实例的使用和实现细节。

1、定义

     ConditionObject是AbstractQueuedSynchronizer的一个内部类,用于实现Condition接口,ReentrantLock通过newCondition方法返回该类的一个实例,如下:

public Condition newCondition() {
        return sync.newCondition();
}

 final ConditionObject newCondition() {
            return new ConditionObject();
        }

Condition接口定义的方法如下:

这里的await相当于Object的wait方法,signal和signalAll方法相当于Object的notify和notifyAll方法。concurrent包下各种阻塞队列和线程池等就是Condition接口实现阻塞,以await方法的调用链为例说明,如下:

  ConditionObject只有两个属性:

  • private transient Node firstWaiter; //在某个Condition实例上等待的Node链表的链表头,即调用了某个condition实例的await方法的等待线程链表
  • private transient Node lastWaiter; //在某个Condition实例上等待的Node链表的链表尾

   注意上述链表是通过Node的nextWaiter构成的单向链表,跟通过Node的prev,next属性构成的等待获取锁的同步链表是不一样的,后者的链表头和链表为分别是AbstractQueuedSynchronizer的head和tail属性。

    ConditionObject还定义了两个常量,描述await方法退出时的处理方式,如下:

REINTERRUPT表示将当前线程的中断标识重置为true,因为之前获取线程是否中断时,会将线程的中断标识给清除掉重置为false,此处是为了还原;THROW_IE表示会抛出一个InterruptedException异常,表示当前线程被唤醒是因为被中断了。 

2、使用

     ConditionObject的await系列方法相当于Object的wait方法,signal和signalAll方法分别对应于Object的notify和notifyAll方法,跟Object一样,执行这些方法前都需要检查当前线程是否持有锁,如果没有持有则会抛出IllegalMonitorStateException异常,ConditionObject的方法和Object的对应方法的实现逻辑也大体一致,参考如下测试用例:

@Test
    public void name2() throws Exception {
        Object lock = new Object();
        Runnable a = new Runnable() {
            @Override
            public void run() {

                try {
                    System.out.println("run start,time->" + System.currentTimeMillis());
                    Thread.sleep(6000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (lock) {
                    lock.notify();
                    System.out.println("run end");
                }
            }
        };
        Thread thread = new Thread(a);
        thread.start();
        synchronized (lock) {
            System.out.println("main start,time->" + System.currentTimeMillis());
            long start = System.currentTimeMillis();
            lock.wait(1000);
            System.out.println("wait time->" + (System.currentTimeMillis() - start));
        }
        System.out.println("main end");
    }

    @Test
    public void name3() throws Exception {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Runnable a = new Runnable() {
            @Override
            public void run() {
                lock.lock();
                try {
                    System.out.println("run start,time->" + System.currentTimeMillis());
                    Thread.sleep(6000);
                    condition.signal();
                    System.out.println("run end");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };
        Thread thread = new Thread(a);
        lock.lock();
        try {
            thread.start();
            System.out.println("main start,time->" + System.currentTimeMillis());
            long start = System.currentTimeMillis();
            condition.await(1, TimeUnit.SECONDS);
            System.out.println("wait time->" + (System.currentTimeMillis() - start));
        } finally {
            lock.unlock();
        }
        System.out.println("main end");
    }

这两个的执行结果一样,如下:

main start,time->1585901311285
run start,time->1585901311286
run end
wait time->6001
main end

wait方法明明最多等待1s,为啥实际等待了6s了,难道是1s后没有被唤醒?答案是调用await和wait方法都会释放当前占有的锁,然后阻塞当前线程;1s过了,阻塞的线程被唤醒了,因为await和wait方法后面的逻辑处于加锁的代码块中,所以线程被唤醒后需要重新去抢占锁,此时锁是被线程thread占用的,所以线程会被唤醒后尝试获取失败又继续被阻塞了,直到6s后thread线程释放锁并唤醒阻塞的main线程,main线程重新获取锁成功,才从await或者wait方法退出,执行下面的逻辑。

3、await / awaitUninterruptibly

     await方法用于让当前线程阻塞,直到被唤醒或者被打断,如果被打断则抛出异常InterruptedException,awaitUninterruptibly会一直等待直到被唤醒,被打断时不会抛出异常,可以通过线程的中断标识判断是否因为中断被唤醒的,注意无论是被signal唤醒的还是被中断唤醒的,都需要再次获取锁才可以退出await方法。

public final void await() throws InterruptedException {
    if (Thread.interrupted())
        //如果线程已中断抛出异常
        throw new InterruptedException();
    //在ConditionWaiter链表末尾插入一个新的状态是CONDITION的节点    
    Node node = addConditionWaiter();
    //释放占有的锁,并唤醒同步队列中下一个等待节点,如果当前线程未持有锁则抛出异常
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    //isOnSyncQueue判断node是否在等待获取锁的同步链表中,对于刚创建的ConditionWaiter节点,没有将其加入到等待获取锁的同步链表中
   //只是将其加入到通过nextWaiter属性维护的等待链表中了,该方法返回false
   //等该节点被signal方法唤醒后就会将其加入到同步链表中了,该方法返回true
    while (!isOnSyncQueue(node)) {
        //执行park让这个线程处于阻塞状态
        LockSupport.park(this);
        //线程被唤醒了,如果线程被中断的话,checkInterruptWhileWaiting的返回值就不是0,此时会退出循环,checkInterruptWhileWaiting在执行时会将当前节点加入到同步链表中
        //如果不是被中断,则继续while循环
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    //acquireQueued方法会尝试获取锁,如果失败则阻塞当前线程直到获取成功,返回值为true,表示最后一次唤醒是因为线程中断
    //interruptMode为0或者REINTERRUPT
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        //从链表中移除所有非CONDITION的节点
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

public final void awaitUninterruptibly() {
            //添加一个新的节点
            Node node = addConditionWaiter();
            //释放锁
            int savedState = fullyRelease(node);
            boolean interrupted = false;
            //判断node是否在同步链表中
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                //如果线程被中断过将interrupted 置为true,此时会继续循环,直到被唤醒,node加入到同步链表中,while循环退出
                if (Thread.interrupted())
                    interrupted = true;
            }
            //如果获取锁成功或者interrupted为true,将当前线程标记为已中断
            if (acquireQueued(node, savedState) || interrupted)
                selfInterrupt();
        }

       
         
//在链表末尾插入一个新的状态是CONDITION的节点,因为此时未释放锁,所以只有一个线程在操作waiter链表,不需要通过CAS修改lastWaiter属性
private Node addConditionWaiter() {
    //获取最后一个节点
    Node t = lastWaiter;
    //如果t不是CONDITION,则从链表中移除所有非CONDITION的节点
    if (t != null && t.waitStatus != Node.CONDITION) {
        unlinkCancelledWaiters();
        t = lastWaiter;
    }
    //创建一个新节点
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    if (t == null)
        //链表为空
        firstWaiter = node;
    else
        //插入到lastWaiter的后面
        t.nextWaiter = node;
    //重置lastWaiter
    lastWaiter = node;
    return node;
}

//会遍历一遍链表,清理掉所有不是CONDITION的节点
private void unlinkCancelledWaiters() {
    Node t = firstWaiter;
    //trail表示上一个非CONDITION节点
    Node trail = null;
    //遍历整个链表
    while (t != null) {
        //获取下一个节点
        Node next = t.nextWaiter;
        if (t.waitStatus != Node.CONDITION) {
            //将t从链表中移除
            t.nextWaiter = null;
            if (trail == null)
                //未找到非CONDITION节点,即之前遍历的节点都被移除了
                firstWaiter = next;
            else
                trail.nextWaiter = next;
            if (next == null)
                //遍历到末尾了,将tail置为lastWaiter
                lastWaiter = trail;
        }
        else
            trail = t;
        t = next;
    }
}

    final int fullyRelease(Node node) {
        boolean failed = true;
        try {
            //获取当前的同步器状态
            int savedState = getState();
            //release方法返回true,表示成功释放锁,返回false表示不能释放锁
            if (release(savedState)) {
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
            if (failed)
                //如果release方法返回false进入此分支,将状态置为CANCELLED
                node.waitStatus = Node.CANCELLED;
        }
    }

   protected final int getState() {
        return state;
    }

    public final boolean release(int arg) {
        //tryRelease是子类实现的方法,会校验当前线程是否持有锁,如果没有则抛出IllegalMonitorStateException异常,如果占有了则用state减去arge,如果等于0返回true,需要释放锁
        if (tryRelease(arg)) {
            //获取链表头
            Node h = head;
            //waitStatus初始值是0
            if (h != null && h.waitStatus != 0)
                //唤醒下一个不是CANCELLED的节点对应的线程
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
 
    //isOnSyncQueue判断node是否在等待获取锁的同步链表中
    final boolean isOnSyncQueue(Node node) {
        //如果是CONDITION则需要从链表中移除
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
        if (node.next != null) // If has successor, it must be on queue
            return true;
        //prev肯定不为空,但是next可能为空,比如该节点就是末尾节点
        return findNodeFromTail(node);
    }

    //从tail开始往前遍历,判断目标节点是否在链表中
    private boolean findNodeFromTail(Node node) {
        Node t = tail;
        for (;;) {
            if (t == node)
                return true;
            if (t == null)
                return false;
            t = t.prev;
        }
    }

    private int checkInterruptWhileWaiting(Node node) {
            return Thread.interrupted() ?
                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
                0;
        }

    final boolean transferAfterCancelledWait(Node node) {
        //如果状态是CONDITION,将其原子的置为0
        if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
            //如果修改成功,将其加入到同步队列中,注意此时node还在等待链表中
            enq(node);
            return true;
        }
        //如果修改失败,说明其他某个线程修改了状态(另一个线程同时唤醒了此节点),则通过isOnSyncQueue方法判断其
        //是否在同步队列中,如果不在则执行yeild,不断while循环,直到该方法返回true
        while (!isOnSyncQueue(node))
            Thread.yield();
        return false;
    }

    private Node enq(final Node node) {
        //for循环直到原子修改成功为止
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    //原子的设置head
                    tail = head;
            } else {
                //tail不为空,将新节点插入到tail的后面
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    //如果原子的修改成功
                    t.next = node;
                    return t;
                }
            }
        }
    }


    private void reportInterruptAfterWait(int interruptMode)
            throws InterruptedException {
            if (interruptMode == THROW_IE)
                //抛出异常
                throw new InterruptedException();
            else if (interruptMode == REINTERRUPT)
                //重新中断当前线程
                selfInterrupt();
        }

测试用例如下:

 @Test
    public void test3() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Condition condition=lock.newCondition();

        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    condition.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        //让a线程执行起来
        Thread.sleep(100);
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    Thread.sleep(5000);
                    condition.signal();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        b.start();
        //让b线程执行起来
        Thread.sleep(100);
        int i=0;
        long start=System.currentTimeMillis();
        while (a.isAlive()){
            a.interrupt();
            i++;
            Thread.sleep(10);
        }
        System.out.println("main thread end,i->"+i+",time->"+(System.currentTimeMillis()-start));
    }

  执行结果如下:

在await方法退出前一共调用interrupt方法489次,从开始调用到await方法退出总耗时4904s,第一次调用interrupt方法会让当前线程从while循环中退出,然后进入到acquireQueued方法尝试获取锁,因为此时线程b在休眠过程中未释放锁,所以进入到acquireQueued方法后会被阻塞,后面每次调用interrupt方法都会唤醒线程然后重新尝试获取锁,直到获取成功为止,从acquireQueued方法退出。退出后因为interruptMode是THROW_IE,然后抛出InterruptedException异常。耗时4904ms是因为执行到start时,线程b实际已经运行了100ms左右,再过4900ms左右,就会执行signal唤醒在condition上等待的线程,线程a获取锁从await方法退出,main线程的while循环终止并退出。

将上述用例换成synchronized关键字,效果是一样的,如下:

@Test
    public void test4() throws Exception {
        Object lock=new Object();

        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    synchronized (lock) {
                        lock.wait();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        a.start();
        //让a线程执行起来
        Thread.sleep(100);
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    synchronized (lock) {
                        Thread.sleep(5000);
                        lock.notify();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        b.start();
        //让b线程执行起来
        Thread.sleep(100);
        int i=0;
        long start=System.currentTimeMillis();
        while (a.isAlive()){
            a.interrupt();
            i++;
            Thread.sleep(10);
        }
        System.out.println("main thread end,i->"+i+",time->"+(System.currentTimeMillis()-start));
    }

如果换成awaitUninterruptibly方法,则不会抛出异常,此时可以通过线程的中断标识来判断是否是因为被中断唤醒的,如下:

@Test
    public void test3() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Condition condition=lock.newCondition();

        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    condition.awaitUninterruptibly();
                    System.out.println("interrupted->"+Thread.currentThread().isInterrupted());
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        //让a线程执行起来
        Thread.sleep(100);
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    Thread.sleep(5000);
                    condition.signal();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        b.start();
        //让b线程执行起来
        Thread.sleep(100);
        int i=0;
        long start=System.currentTimeMillis();
        while (a.isAlive()){
            a.interrupt();
            i++;
            Thread.sleep(10);
        }
        System.out.println("main thread end,i->"+i+",time->"+(System.currentTimeMillis()-start));
    }

测试结果如下:

4、await / awaitNanos / awaitUntil

     上面的await是没有时间参数的,带时间参数的await方法有三个版本,await方法被中断唤醒后会尝试获取锁并抛出异常,如果是被signal唤醒的,则返回等待时间是否超时了,返回false表示等待超时了,true表示没有被超时。awaitNanos的实现跟await基本一致,就返回值不同,awaitNanos返回剩余的等待时间,如果为负值,表示等待超时了,否则未超时。awaitUntil的实现及返回值都和await一致,但是入参不同,await传递的是相对时间,从线程开始休眠算起,awaitUntil传递的是绝对时间,即具体的某一个时间点。

//返回是否因等待超时被唤醒,false表示等待超时了,true表示没有等待超时
public final boolean await(long time, TimeUnit unit)
                throws InterruptedException {
            long nanosTimeout = unit.toNanos(time);
            if (Thread.interrupted())
                //如果线程中断,则抛出异常
                throw new InterruptedException();
            //添加一个ConditionWaiter节点    
            Node node = addConditionWaiter();
            //释放锁
            int savedState = fullyRelease(node);
            //计算等待的最迟期限
            final long deadline = System.nanoTime() + nanosTimeout;
            boolean timedout = false;
            int interruptMode = 0;
            //判断node是否在同步等待队列中
            while (!isOnSyncQueue(node)) {
                if (nanosTimeout <= 0L) {
                    //等待的时间到了
                    timedout = transferAfterCancelledWait(node);
                    break;
                }
                //等待的时间较长,将线程park
                if (nanosTimeout >= spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                //线程被唤醒,如果线程被中断则checkInterruptWhileWaiting返回1或者-1,终止循环
                //如果是被signal方法唤醒则检查node是否在同步链表中,如果在则退出循环,尝试获取锁
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
                //线程是被signal方法唤醒的,重新计算等待的时间    
                nanosTimeout = deadline - System.nanoTime();
            }
            //这部分逻辑跟不带参数的await方法一致
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null)
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
            return !timedout;
        }


//awaitNanos的逻辑和带时间参数的await方法实现一致,就是返回值不同,返回剩余的等待时间
public final long awaitNanos(long nanosTimeout)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();
            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();
        }

//跟上面两个相比就是等待的时间不一致,上面两个是相对时间,从进入方法开始算起的,awaitUntil是绝对时间,即一个固定的时间点
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;
                }
                //abstime是绝对时间
                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;
        }

测试用例如下:

@Test
    public void test3() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Condition condition=lock.newCondition();
        CountDownLatch countDownLatch=new CountDownLatch(1);

        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
//                    boolean result=condition.await(6, TimeUnit.SECONDS);
//                    long result=condition.awaitNanos(TimeUnit.SECONDS.toNanos(4));
                    Calendar calendar= Calendar.getInstance();
                    calendar.add(Calendar.SECOND,5);
                    boolean result=condition.awaitUntil(calendar.getTime());
                    System.out.println("await result->"+result);
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        //让a线程执行起来
        Thread.sleep(100);
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    Thread.sleep(5000);
                    condition.signal();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        b.start();
        //让b线程执行起来
        Thread.sleep(100);
        long start=System.currentTimeMillis();
        countDownLatch.await();
        System.out.println("main thread end,time->"+(System.currentTimeMillis()-start));
    }

 5、signal / signalAll

      signal和signalAll的核心都是transferForSignal方法,区别在于前者只处理firstWaiter一个节点,而signalAll会处理所有的节点。transferForSignal方法并不会直接唤醒等待中的线程,而是将其加入到等待获取锁的同步链表的后面,然后将该节点的前一个节点的状态改成SIGNAL,表示需要唤醒该节点。等同步链表前面的节点都获取锁并释放锁后,才会让该节点获取锁。

public final void signal() {
            //如果没有获取锁,则抛出异常
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
        }


public final void signalAll() {
            //如果没有获取锁,则抛出异常
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignalAll(first);
        }

 private void doSignal(Node first) {
            do {
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
            } while (!transferForSignal(first) && //如果first是一个CANCLE节点,则transferForSignal返回false,然后通过while循环处理下一个节点
                                                  //否则返回true,终止循环
                     (first = firstWaiter) != null);
        }

final boolean transferForSignal(Node node) {
    
        //将node的状态由CONDITION修改成0,如果修改失败,说明不是CONDITION而是CANCLE
        //即node是一个无效节点
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;

        //将node插入到同步链表的末尾,返回链表中node的上一个节点,即插入前的tail节点
        Node p = enq(node);
        int ws = p.waitStatus;
        //如果上一个节点是CANCLE,说明当前互斥锁未被占用,可唤醒当前线程获取锁
        //将上一个tail节点状态为SIGNAL失败,说明该节点就是head节点,且head节点准备释放锁将状态置为0
        //正常情形就是将p的状态修改成SIGNAL,
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }

private void doSignalAll(Node first) {
            //first本身就是firstWaiter,所以此处可以先将lastWaiter和firstWaiter置为null
            lastWaiter = firstWaiter = null;
            do {
                //从first开始遍历所有的节点
                Node next = first.nextWaiter;
                first.nextWaiter = null;
                //将目标节点加入到同步队列中
                transferForSignal(first);
                first = next;
            } while (first != null);
        }

  测试用例如下:

 @Test
    public void test() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Condition condition=lock.newCondition();
        CountDownLatch countDownLatch=new CountDownLatch(8);
        Runnable wait=new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    lock.lock();
                    condition.await();
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName()+",await time->"+System.nanoTime());
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        };
        for(int i=0;i<5;i++){
            Thread thread=new Thread(wait);
            thread.start();
        }
        //让上面5个线程运行起来并进入到await等待链表中
        Thread.sleep(2000);
        System.out.println("all wait thread start");
        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    lock.lock();
                    Thread.sleep(5000);
                    //根据awaiter队列的顺序,将await的线程加入到同步队列中
                    condition.signalAll();
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        //让线程a运行起来,进入sleep
        Thread.sleep(100);
        //让线程b和线程c加入到同步队列中
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    lock.lock();
                    System.out.println(Thread.currentThread().getName()+",lock time->"+System.nanoTime());
                    Thread.sleep(1000);
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        b.start();
        Thread c=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    lock.lock();
                    System.out.println(Thread.currentThread().getName()+",lock time->"+System.nanoTime());
                    Thread.sleep(1000);
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        c.start();

        countDownLatch.await();
        System.out.println("main thread end");
    }

 其输出如下:

#从上到下,5个线程依次启动,并依次加入到await等待链表中
Thread-0,start time->2257452263025112
Thread-4,start time->2257452264363671
Thread-2,start time->2257452264494532
Thread-1,start time->2257452265047514
Thread-3,start time->2257452265350669
all wait thread start
//线程b和c都起来了,进入等待锁的同步链表中
Thread-6,start time->2257454364189121
Thread-7,start time->2257454364855324
//线程b和c依次获取锁
Thread-6,lock time->2257459262985730
Thread-7,lock time->2257460262757235
//5个线程按照加入到await等待链表中的顺序依次被唤醒获取锁
Thread-0,await time->2257461362593351
Thread-4,await time->2257461462572635
Thread-2,await time->2257461562551508
Thread-1,await time->2257461662549663
Thread-3,await time->2257461762404238
main thread end

 在默认的非公平锁下,最早加入等待获取锁的同步链表中的线程优先获取锁,当在某个condition实例上等待的线程被唤醒后,是加入到同步链表的末尾等待获取锁;而synchronized的实现是相反的,最近加入到同步链表中的线程优先获取锁,当在某个Object实例上等待的线程被唤醒后,是加入到同步链表的前面,最近才加入到等待链表中线程在同步链表中的位置越靠前。测试用例如下:
 

 @Test
    public void test2() throws Exception {
        Object lock=new Object();
        CountDownLatch countDownLatch=new CountDownLatch(8);
        Runnable wait=new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    synchronized (lock) {
                        lock.wait();
                        Thread.sleep(100);
                    }
                    System.out.println(Thread.currentThread().getName()+",await time->"+System.nanoTime());
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        for(int i=0;i<5;i++){
            Thread thread=new Thread(wait);
            thread.start();
        }
        Thread.sleep(2000);
        System.out.println("all wait thread start");
        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    synchronized (lock) {
                        Thread.sleep(5000);
                        lock.notifyAll();
                    }
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        a.start();
        Thread.sleep(100);
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    synchronized (lock) {
                        System.out.println(Thread.currentThread().getName() + ",lock time->" + System.nanoTime());
                        Thread.sleep(1000);
                    }
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        b.start();
        Thread c=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName()+",start time->"+System.nanoTime());
                    synchronized (lock) {
                        System.out.println(Thread.currentThread().getName() + ",lock time->" + System.nanoTime());
                        Thread.sleep(1000);
                    }
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        c.start();

        countDownLatch.await();
        System.out.println("main thread end");
    }

执行结果如下:

# 5个线程依次启动,进入等待链表中
Thread-0,start time->2257752210301534
Thread-1,start time->2257752211441136
Thread-4,start time->2257752213288373
Thread-2,start time->2257752213312986
Thread-3,start time->2257752214007084
all wait thread start
//线程 b和c依次启动,进入同步链表中
Thread-6,start time->2257754313978574
Thread-7,start time->2257754314997979
//线程a开始释放锁,notifyAll将所有等待链表中的节点按照相反的顺序加入到同步链表的前面
//按照同步链表的顺序依次唤醒线程,最近加入的优先被唤醒
Thread-3,await time->2257759311780596
Thread-2,await time->2257759411766853
Thread-4,await time->2257759511758033
Thread-1,await time->2257759611688911
Thread-0,await time->2257759711730959
Thread-7,lock time->2257759711767879
Thread-6,lock time->2257760711589432
main thread end

6、其他方法实现总结

     ReentrantLock中有多个可以查看Condition等待队列状态的方法,其实现比较简单,这里总结如下:

  • getWaitingThreads:获取在某个Condition实例上等待的线程列表,从firstWaiter开始往后遍历,将所有状态是CONDITION的节点对应的Thread加入到列表中并返回即可。
  • getWaitQueueLength:获取在某个Condition实例上等待的线程的个数,遍历方式同上,不过此方法是计数累加
  • hasWaiters:判断在某个Condition实例上是否有等待的线程,遍历方式同上,不过找到一个状态是CONDITION的节点即返回true

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章