Java并发20:Lock系列-Condition接口基本方法学习实例

本章主要通过解读Condition接口的源码注释,来学习Condition接口的各个方法。

1.Condition接口与Lock接口

在Java并发18章节,我们对Lock接口与synchronized关键字的区别于联系进行了学习。

其实在功能上,我们可以将Lock接口作为synchronized关键字的升级版。

在Java并发07章节,而我们已知,obj.wati()/obj.notify()/obj.notifyAll常用来与synchronized关键字合作,进行线程状态控制。

同样的,Condition接口也提供了一系列比obj.wati()/obj.notify()/obj.notifyAll更加灵活和丰富的方法和Lock接口合作,进行线程状态控制

2.JDK源码注释

public interface Condition {

    /**
     * Causes the current thread to wait until it is signalled or
     * {@linkplain Thread#interrupt interrupted}.
     *
     * <p>The lock associated with this {@code Condition} is atomically
     * released and the current thread becomes disabled for thread scheduling
     * purposes and lies dormant until <em>one</em> of four things happens:
     * <ul>
     * <li>Some other thread invokes the {@link #signal} method for this
     * {@code Condition} and the current thread happens to be chosen as the
     * thread to be awakened; or
     * <li>Some other thread invokes the {@link #signalAll} method for this
     * {@code Condition}; or
     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
     * current thread, and interruption of thread suspension is supported; or
     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
     * </ul>
     *
     * <p>In all cases, before this method can return the current thread must
     * re-acquire the lock associated with this condition. When the
     * thread returns it is <em>guaranteed</em> to hold this lock.
     *
     * <p>If the current thread:
     * <ul>
     * <li>has its interrupted status set on entry to this method; or
     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
     * and interruption of thread suspension is supported,
     * </ul>
     * then {@link InterruptedException} is thrown and the current thread's
     * interrupted status is cleared. It is not specified, in the first
     * case, whether or not the test for interruption occurs before the lock
     * is released.
     * ...
     */
    void await() throws InterruptedException;

    /**
     * Causes the current thread to wait until it is signalled.
     *
     * <p>The lock associated with this condition is atomically
     * released and the current thread becomes disabled for thread scheduling
     * purposes and lies dormant until <em>one</em> of three things happens:
     * <ul>
     * <li>Some other thread invokes the {@link #signal} method for this
     * {@code Condition} and the current thread happens to be chosen as the
     * thread to be awakened; or
     * <li>Some other thread invokes the {@link #signalAll} method for this
     * {@code Condition}; or
     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
     * </ul>
     *
     * <p>In all cases, before this method can return the current thread must
     * re-acquire the lock associated with this condition. When the
     * thread returns it is <em>guaranteed</em> to hold this lock.
     *
     * <p>If the current thread's interrupted status is set when it enters
     * this method, or it is {@linkplain Thread#interrupt interrupted}
     * while waiting, it will continue to wait until signalled. When it finally
     * returns from this method its interrupted status will still
     * be set.
     * ...
     */
    void awaitUninterruptibly();

    /**
     * Causes the current thread to wait until it is signalled or interrupted,
     * or the specified waiting time elapses.
     *
     * <p>The lock associated with this condition is atomically
     * released and the current thread becomes disabled for thread scheduling
     * purposes and lies dormant until <em>one</em> of five things happens:
     * <ul>
     * <li>Some other thread invokes the {@link #signal} method for this
     * {@code Condition} and the current thread happens to be chosen as the
     * thread to be awakened; or
     * <li>Some other thread invokes the {@link #signalAll} method for this
     * {@code Condition}; or
     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
     * current thread, and interruption of thread suspension is supported; or
     * <li>The specified waiting time elapses; or
     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
     * </ul>
     *
     * <p>In all cases, before this method can return the current thread must
     * re-acquire the lock associated with this condition. When the
     * thread returns it is <em>guaranteed</em> to hold this lock.
     *
     * <p>If the current thread:
     * <ul>
     * <li>has its interrupted status set on entry to this method; or
     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
     * and interruption of thread suspension is supported,
     * </ul>
     * then {@link InterruptedException} is thrown and the current thread's
     * interrupted status is cleared. It is not specified, in the first
     * case, whether or not the test for interruption occurs before the lock
     * is released.
     *
     * <p>The method returns an estimate of the number of nanoseconds
     * remaining to wait given the supplied {@code nanosTimeout}
     * value upon return, or a value less than or equal to zero if it
     * timed out. This value can be used to determine whether and how
     * long to re-wait in cases where the wait returns but an awaited
     * condition still does not hold. Typical uses of this method take
     * the following form:
     *
     *  <pre> {@code
     * boolean aMethod(long timeout, TimeUnit unit) {
     *   long nanos = unit.toNanos(timeout);
     *   lock.lock();
     *   try {
     *     while (!conditionBeingWaitedFor()) {
     *       if (nanos <= 0L)
     *         return false;
     *       nanos = theCondition.awaitNanos(nanos);
     *     }
     *     // ...
     *   } finally {
     *     lock.unlock();
     *   }
     * }}</pre>
     *
     * <p>Design note: This method requires a nanosecond argument so
     * as to avoid truncation errors in reporting remaining times.
     * Such precision loss would make it difficult for programmers to
     * ensure that total waiting times are not systematically shorter
     * than specified when re-waits occur.
     * ...
     */
    long awaitNanos(long nanosTimeout) throws InterruptedException;

    /**
     * Causes the current thread to wait until it is signalled or interrupted,
     * or the specified waiting time elapses. This method is behaviorally
     * equivalent to:
     *  <pre> {@code awaitNanos(unit.toNanos(time)) > 0}</pre>
     *
     * @param time the maximum time to wait
     * @param unit the time unit of the {@code time} argument
     * @return {@code false} if the waiting time detectably elapsed
     *         before return from the method, else {@code true}
     * @throws InterruptedException if the current thread is interrupted
     *         (and interruption of thread suspension is supported)
     */
    boolean await(long time, TimeUnit unit) throws InterruptedException;

    /**
     * Causes the current thread to wait until it is signalled or interrupted,
     * or the specified deadline elapses.
     *
     * <p>The lock associated with this condition is atomically
     * released and the current thread becomes disabled for thread scheduling
     * purposes and lies dormant until <em>one</em> of five things happens:
     * <ul>
     * <li>Some other thread invokes the {@link #signal} method for this
     * {@code Condition} and the current thread happens to be chosen as the
     * thread to be awakened; or
     * <li>Some other thread invokes the {@link #signalAll} method for this
     * {@code Condition}; or
     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
     * current thread, and interruption of thread suspension is supported; or
     * <li>The specified deadline elapses; or
     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
     * </ul>
     *
     * <p>In all cases, before this method can return the current thread must
     * re-acquire the lock associated with this condition. When the
     * thread returns it is <em>guaranteed</em> to hold this lock.
     *
     *
     * <p>If the current thread:
     * <ul>
     * <li>has its interrupted status set on entry to this method; or
     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
     * and interruption of thread suspension is supported,
     * </ul>
     * then {@link InterruptedException} is thrown and the current thread's
     * interrupted status is cleared. It is not specified, in the first
     * case, whether or not the test for interruption occurs before the lock
     * is released.
     *
     *
     * <p>The return value indicates whether the deadline has elapsed,
     * which can be used as follows:
     *  <pre> {@code
     * boolean aMethod(Date deadline) {
     *   boolean stillWaiting = true;
     *   lock.lock();
     *   try {
     *     while (!conditionBeingWaitedFor()) {
     *       if (!stillWaiting)
     *         return false;
     *       stillWaiting = theCondition.awaitUntil(deadline);
     *     }
     *     // ...
     *   } finally {
     *     lock.unlock();
     *   }
     * }}</pre>
     *
     * ...
     */
    boolean awaitUntil(Date deadline) throws InterruptedException;

    /**
     * Wakes up one waiting thread.
     *
     * <p>If any threads are waiting on this condition then one
     * is selected for waking up. That thread must then re-acquire the
     * lock before returning from {@code await}.
     * ...
     */
    void signal();

    /**
     * Wakes up all waiting threads.
     *
     * <p>If any threads are waiting on this condition then they are
     * all woken up. Each thread must re-acquire the lock before it can
     * return from {@code await}.
     * ...
     */
    void signalAll();
}

3.源码解读

通过解读上面的源码,将Condition接口提供的方法总结如下:

1.void await() throws InterruptedException;

  • 当前线程进入等待状态,直到它被唤醒或被中断。
  • 与当前Condition对象相关联的Lock锁会自动释放
  • 为了线程调度目的,当前线程会变为不可用的,直到出现以下四种情形之一:
  1. 其他线程调用了当前Condition对象的signal()方法,并且当前线程恰好被选为被唤醒线程
  2. 其他线程调用了当前Condition对象的signalAll()方法
  3. 其他线程调用了当前线程的interrupt()方法,而当前线程支持线程中断
  4. 产生虚假唤醒。
  • 以上所有的情形中,在awit()方法返回之前,当前线程必须重新获取与当前Condition对象相关联的Lock锁
  • 在执行awit()方法过程中,如果当前线程被中断(interrupt())了,则会抛出一个InterruptedException异常,并将中断状态重置。

2.void awaitUninterruptibly();

  • 让当前线程进入等待状态,直到它被唤醒。
  • 与当前Condition对象相关联的Lock锁会自动释放
  • 为了线程调度目的,当前线程会变为不可用的,直到出现以下三种情形之一:
  1. 其他线程调用了当前Condition对象的signal()方法,并且当前线程恰好被选为被唤醒线程。
  2. 其他线程调用了当前Condition对象的signalAll()方法
  3. 产生虚假唤醒。
  • 以上所有的情形中,在awit()方法返回之前,当前线程必须重新获取与当前Condition对象相关联的Lock锁
  • 该等待不可中断

3.long awaitNanos(long nanosTimeout) throws InterruptedException;

  • 让当前线程进入等待状态,直到它被唤醒、被中断或限定时间超时。
  • 与当前Condition对象相关联的Lock锁会自动释放
  • 为了线程调度目的,当前线程会变为不可用的,直到出现以下五种情形之一:
  1. 其他线程调用了当前Condition对象的signal()方法,并且当前线程恰好被选为被唤醒线程。
  2. 其他线程调用了当前Condition对象的signalAll()方法
  3. 其他线程调用了当前线程的interrupt()方法,而当前线程支持线程中断
  4. 限定的等待时间超时
  5. 产生虚假唤醒。
  • 以上所有的情形中,在awit()方法返回之前,当前线程必须重新获取与当前Condition对象相关联的Lock锁
  • 在执行awit()方法过程中,如果当前线程被中断(interrupt())了,则会抛出一个InterruptedException异常,并将中断状态重置。
  • 这个方法会返回剩余的等待时间;如果已经超时,则返回值可能是0或负值。这个值可以用来确定是否还要继续等待。使用纳秒是为了进行精度控制。通常这个方法的用法如下:
boolean aMethod(long timeout, TimeUnit unit) {
  //获取纳秒
  long nanos = unit.toNanos(timeout);
  //加锁
  lock.lock();
  try {
    //如果继续等待
    while (!conditionBeingWaitedFor()) {
      //如果已经超时,则...
      if (nanos <= 0L)
        return false;
      //获取剩余等待时间
      nanos = theCondition.awaitNanos(nanos);
    }
    // ...
  } finally {
    //解锁
    lock.unlock();
  }
}

4.boolean await(long time, TimeUnit unit) throws InterruptedException;

  • 让当前线程进入等待状态,直到它被唤醒、被中断或限定时间超时。
  • 这个方法等同于awaitNanos(unit.toNanos(time)) > 0,不再赘述。

5.boolean awaitUntil(Date deadline) throws InterruptedException;

  • 让当前线程进入等待状态,直到它被唤醒、被中断或截止时间过去。
  • 与当前Condition对象相关联的Lock锁会自动释放。
  • 为了线程调度目的,当前线程会变为不可用的,直到出现以下五种情形之一:
  1. 其他线程调用了当前Condition对象的signal()方法,并且当前线程恰好被选为被唤醒线程。
  2. 其他线程调用了当前Condition对象的signalAll()方法
  3. 其他线程调用了当前线程的interrupt()方法,而当前线程支持线程中断。
  4. 指定的截止时间已经过去。
  5. 产生虚假唤醒。
  • 以上所有的情形中,在awit()方法返回之前,当前线程必须重新获取与当前Condition对象相关联的Lock锁。
  • 在执行awit()方法过程中,如果当前线程被中断(interrupt())了,则会抛出一个InterruptedException异常,并将中断状态重置。
  • 这个方法的返回值表示截止时间是否已经过去

通常这个方法的用法如下:

boolean aMethod(Date deadline) {
  boolean stillWaiting = true;
  //加锁
  lock.lock();
  try {
    //如果继续等待
    while (!conditionBeingWaitedFor()) {
      if (!stillWaiting)
        return false;
      //获取指定的截止时间已经过去
      stillWaiting = theCondition.awaitUntil(deadline);
    }
    // ...
  } finally {
    //解锁
    lock.unlock();
  }
}

6.void signal();

  • 唤醒一个线程。
  • 如果当前的Condition对象上有等待的线程,则唤醒其中的一个线程
  • 这个被唤醒的线程必须在从awit()方法返回之前重新获取锁

7.void signalAll();

  • 唤醒所有线程。
  • 如果当前的Condition对象上有等待的线程,则唤醒全部的线程
  • 每个被唤醒的线程必须在从awit()方法返回之前重新获取锁。

4.实例代码

实例场景:

  • 定义5个等待线程如下:
    • 线程0:通过await()进行等待。
    • 线程1:通过awaitNanos(long)进行等待,long=1000000000,即1秒钟。
    • 线程2:通过await(long,TimeUnit)进行等待,long=2,TimeUnit=TimeUnit.SECONDS,即2秒钟。
    • 线程3:通过awaitUntil(deadline)进行等待,System.currentTimeMillis() + 5000,即5秒之后的时刻。
    • 线程4:通过awaitUninterruptibly()进行等待。
  • 定义3种测试场景:
    • 等待所有线程自己结束。
    • 在5个测试线程启动100毫秒之后,通过interrupt()中断所有线程。
    • 在5个测试线程启动100毫秒之后,通过condition.signalAll()唤醒所有线程。

结果预测:

  • 场景一:等待所有线程自己结束。
    • 线程0:通过await()等待,此方法只能被中断和被唤醒,所以此线程不会终止
    • 线程1:通过awaitNanos(long)等待1秒钟,此方法可被中断、被唤醒或者超时,所以线程会在1秒之后自动终止
    • 线程2:通过await(long,TimeUnit)等待2秒钟,此方法可被中断、被唤醒或者超时,所以线程会在2秒之后自动终止
    • 线程3:通过awaitUntil(deadline)等待至5秒之后,此方法可被中断、被唤醒或者到期,所以线程会在5秒之后自动终止
    • 线程4:通过awaitUninterruptibly()等待,此方法只能被唤醒,所以此线程不会终止
  • 在5个测试线程启动100毫秒之后,通过interrupt()中断所有线程
    • 线程0:通过await()等待,此方法可被中断和被唤醒,所以此线程会因为被中断而终止。
    • 线程1:通过awaitNanos(long)等待1秒钟,此方法可被中断、被唤醒或者超时,所以此线程会因为被中断而终止。
    • 线程2:通过await(long,TimeUnit)等待2秒钟,此方法可被中断、被唤醒或者超时,所以此线程会因为被中断而终止。
    • 线程3:通过awaitUntil(deadline)等待至5秒之后,此方法可被中断、被唤醒或者到期,所以此线程会因为被中断而终止。
    • 线程4:通过awaitUninterruptibly()等待,此方法只能被唤醒,所以此线程不会终止
  • 在5个测试线程启动100毫秒之后,通过condition.signalAll()唤醒所有线程。
    • 线程0:通过await()等待,此方法可被中断和被唤醒,所以此线程会因为被唤醒而终止。
    • 线程1:通过awaitNanos(long)等待1秒钟,此方法可被中断、被唤醒或者超时,所以此线程会因为被唤醒而终止。
    • 线程2:通过await(long,TimeUnit)等待2秒钟,此方法可被中断、被唤醒或者超时,所以此线程会因为被唤醒而终止。
    • 线程3:通过awaitUntil(deadline)等待至5秒之后,此方法可被中断、被唤醒或者到期,所以此线程会因为被唤醒而终止。
    • 线程4:通过awaitUninterruptibly()等待,此方法只能被唤醒,所以此线程会因为被唤醒而终止。

实例代码:

/**
 * <p>Lock接口-Condition学习-可中断锁、可定时锁</p>
 *
 * @author hanchao 2018/3/18 14:45
 **/
public class ConditionDemo {
    //定义一个非公平的锁
    private static Lock lock = new ReentrantLock(false);

    /**
     * <p>Lock接口-Condition学习</p>
     *
     * @author hanchao 2018/3/18 14:46
     **/
    public static void main(String[] args) throws InterruptedException {
        Condition condition = lock.newCondition();
        //线程0:通过await()进行等待,直到被中断或者被唤醒
        Thread thread0 = new Thread(() -> {
            System.out.println("线程[await()-" + Thread.currentThread().getName() + "]尝试获取锁...");
            lock.lock();
            System.out.println("线程[await()-" + Thread.currentThread().getName() + "]获取了锁.");
            try {
                //通过await()进行等待,直到被中断或者被唤醒
                condition.await();
                System.out.println("线程[await()-" + Thread.currentThread().getName() + "]被唤醒...");
            } catch (InterruptedException e) {
                //e.printStackTrace();
                System.out.println("线程[await()-" + Thread.currentThread().getName() + "]被中断...");
            } finally {
                lock.unlock();
                System.out.println("线程[await()-" + Thread.currentThread().getName() + "]释放了锁.");
            }
        });
        //线程1:通过awaitNanos(long)进行等待,直到被中断、被唤醒、或时间超时
        Thread thread1 = new Thread(() -> {
            System.out.println("线程[awaitNanos(long)-" + Thread.currentThread().getName() + "]尝试获取锁...");
            lock.lock();
            System.out.println("线程[awaitNanos(long)-" + Thread.currentThread().getName() + "]获取了锁.");
            try {
                //通过awaitNanos(long)进行等待,直到被中断、被唤醒或时间用尽
                //剩余等待时间
                Long remainTime = condition.awaitNanos(1000000000);//等待1秒钟
                if (remainTime > 0) {//如果剩余时间大于0,则表明此线程是被唤醒的
                    System.out.println("线程[awaitNanos(long)-" + Thread.currentThread().getName() + "]被唤醒...");
                } else {//如果剩余时间小于等于0,则表明此线程是因为等待时间耗尽而停止等待的
                    System.out.println("线程[awaitNanos(long)-" + Thread.currentThread().getName() + "]等待时间用尽,停止等待...");
                }
            } catch (InterruptedException e) {
                //e.printStackTrace();
                System.out.println("线程[awaitNanos(long)-" + Thread.currentThread().getName() + "]被中断...");
            } finally {
                //尝试解锁
                lock.unlock();
                System.out.println("线程[awaitNanos(long)-" + Thread.currentThread().getName() + "]释放了锁.");
            }
        });
        //线程2:通过await(long,TimeUnit)进行等待,直到被中断、被唤醒、或时间超时
        Thread thread2 = new Thread(() -> {
            System.out.println("线程[await(long,TimeUnit)-" + Thread.currentThread().getName() + "]尝试获取锁...");
            lock.lock();
            System.out.println("线程[await(long,TimeUnit)-" + Thread.currentThread().getName() + "]获取了锁.");
            try {
                //通过awaitNanos(long)进行等待,直到被中断、被唤醒或时间用尽
                //返回true则表明是被唤醒的,false表明是时间用尽
                boolean result = condition.await(2, TimeUnit.SECONDS);//等待2秒钟
                if (result) {
                    System.out.println("线程[await(long,TimeUnit)-" + Thread.currentThread().getName() + "]被唤醒...");
                } else {
                    System.out.println("线程[await(long,TimeUnit)-" + Thread.currentThread().getName() + "]等待时间用尽,停止等待...");
                }
            } catch (InterruptedException e) {
                //e.printStackTrace();
                System.out.println("线程[await(long,TimeUnit)-" + Thread.currentThread().getName() + "]被中断...");
            } finally {
                //尝试解锁
                lock.unlock();
                System.out.println("线程[await(long,TimeUnit)-" + Thread.currentThread().getName() + "]释放了锁.");
            }
        });
        //线程3:通过awaitUntil(deadline)进行等待,直到被中断、被唤醒、或时间到期
        Thread thread3 = new Thread(() -> {
            System.out.println("线程[awaitUntil(deadline)-" + Thread.currentThread().getName() + "]尝试获取锁...");
            lock.lock();
            System.out.println("线程[awaitUntil(deadline)-" + Thread.currentThread().getName() + "]获取了锁.");
            try {
                Date deadline = new Date(System.currentTimeMillis() + 5000);//5秒之后
                //通过awaitUntil(deadline)进行等待,直到被中断、被唤醒或到达截止时间
                //返回true则表明是被唤醒的,false表明是时间用尽
                boolean result = condition.awaitUntil(deadline);
                if (result) {
                    System.out.println("线程[awaitUntil(deadline)-" + Thread.currentThread().getName() + "]被唤醒...");
                } else {
                    System.out.println("线程[awaitUntil(deadline)-" + Thread.currentThread().getName() + "]到达截止时间,停止等待...");
                }
            } catch (InterruptedException e) {
                //e.printStackTrace();
                System.out.println("线程[awaitUntil(deadline)-" + Thread.currentThread().getName() + "]被中断...");
            } finally {
                //尝试解锁
                lock.unlock();
                System.out.println("线程[awaitUntil(deadline)-" + Thread.currentThread().getName() + "]释放了锁.");
            }
        });
        //线程4:通过awaitUninterruptibly()进行等待,直到被唤醒
        Thread thread4 = new Thread(() -> {
            System.out.println("线程[awaitUninterruptibly()-" + Thread.currentThread().getName() + "]尝试获取锁...");
            lock.lock();
            System.out.println("线程[awaitUninterruptibly()-" + Thread.currentThread().getName() + "]获取了锁.");
            try {
                //通过awaitUninterruptibly()进行等待,直到被唤醒
                condition.awaitUninterruptibly();
                System.out.println("线程[awaitUninterruptibly()-" + Thread.currentThread().getName() + "]被唤醒...");
            } finally {
                //尝试解锁
                lock.unlock();
                System.out.println("线程[awaitUninterruptibly()-" + Thread.currentThread().getName() + "]释放了锁.");
            }
        });
        //启动所有线程
        thread0.start();
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        /**
         * 0 等待线程自己结束
         * 1 通过中断结束线程
         * 2 通过condition.signalAll()唤醒所有线程
         */
        int type = 2;
        switch (type) {
            case 0:
                //让能自己结束的自己结束
                Thread.sleep(100);
                System.out.println("======================等待线程自己结束");
                break;
            case 1:
                //尝试中断线程
                Thread.sleep(100);
                System.out.println("======================尝试中断线程");
                thread0.interrupt();
                thread1.interrupt();
                thread2.interrupt();
                thread3.interrupt();
                thread4.interrupt();
                break;
            case 2:
                Thread.sleep(100);
                System.out.println("======================开始唤醒所有还在等待的线程");
                //在main线程中,通过condition.signalAll()唤醒所有
                System.out.println("线程[condition.signalAll()-" + Thread.currentThread().getName() + "]尝试获取锁...");
                lock.lock();
                System.out.println("线程[condition.signalAll()-" + Thread.currentThread().getName() + "]获取了锁,并唤醒所有等待的线程...");
                try {
                    //通过awaitUninterruptibly()进行等待,直到被唤醒
                    condition.signalAll();
                } finally {
                    //尝试解锁
                    lock.unlock();
                    System.out.println("线程[condition.signalAll()-" + Thread.currentThread().getName() + "]释放了锁.");
                }
                break;
            default:
                break;
        }
    }
}

运行结果:

  • 等待所有线程自己结束。
线程[awaitNanos(long)-Thread-1]尝试获取锁...
线程[awaitNanos(long)-Thread-1]获取了锁.
线程[awaitUntil(deadline)-Thread-3]尝试获取锁...
线程[awaitUntil(deadline)-Thread-3]获取了锁.
线程[await(long,TimeUnit)-Thread-2]尝试获取锁...
线程[awaitUninterruptibly()-Thread-4]尝试获取锁...
线程[await()-Thread-0]尝试获取锁...
线程[await(long,TimeUnit)-Thread-2]获取了锁.
线程[awaitUninterruptibly()-Thread-4]获取了锁.
线程[await()-Thread-0]获取了锁.
======================等待线程自己结束
线程[awaitNanos(long)-Thread-1]等待时间用尽,停止等待...
线程[awaitNanos(long)-Thread-1]释放了锁.
线程[await(long,TimeUnit)-Thread-2]等待时间用尽,停止等待...
线程[await(long,TimeUnit)-Thread-2]释放了锁.
线程[awaitUntil(deadline)-Thread-3]到达截止时间,停止等待...
线程[awaitUntil(deadline)-Thread-3]释放了锁.

在5个测试线程启动100毫秒之后,通过interrupt()中断所有线程。

线程[await()-Thread-0]尝试获取锁...
线程[await(long,TimeUnit)-Thread-2]尝试获取锁...
线程[awaitNanos(long)-Thread-1]尝试获取锁...
线程[awaitUntil(deadline)-Thread-3]尝试获取锁...
线程[awaitUninterruptibly()-Thread-4]尝试获取锁...
线程[await()-Thread-0]获取了锁.
线程[await(long,TimeUnit)-Thread-2]获取了锁.
线程[awaitNanos(long)-Thread-1]获取了锁.
线程[awaitUntil(deadline)-Thread-3]获取了锁.
线程[awaitUninterruptibly()-Thread-4]获取了锁.
======================尝试中断线程
线程[awaitNanos(long)-Thread-1]被中断...
线程[awaitNanos(long)-Thread-1]释放了锁.
线程[await()-Thread-0]被中断...
线程[await()-Thread-0]释放了锁.
线程[await(long,TimeUnit)-Thread-2]被中断...
线程[await(long,TimeUnit)-Thread-2]释放了锁.
线程[awaitUntil(deadline)-Thread-3]被中断...
线程[awaitUntil(deadline)-Thread-3]释放了锁.

在5个测试线程启动100毫秒之后,通过condition.signalAll()唤醒所有线程。

线程[awaitNanos(long)-Thread-1]尝试获取锁...
线程[await()-Thread-0]尝试获取锁...
线程[await(long,TimeUnit)-Thread-2]尝试获取锁...
线程[awaitUntil(deadline)-Thread-3]尝试获取锁...
线程[awaitNanos(long)-Thread-1]获取了锁.
线程[awaitUninterruptibly()-Thread-4]尝试获取锁...
线程[awaitUninterruptibly()-Thread-4]获取了锁.
线程[await()-Thread-0]获取了锁.
线程[await(long,TimeUnit)-Thread-2]获取了锁.
线程[awaitUntil(deadline)-Thread-3]获取了锁.
======================开始唤醒所有还在等待的线程
线程[condition.signalAll()-main]尝试获取锁...
线程[condition.signalAll()-main]获取了锁,并唤醒所有等待的线程...
线程[condition.signalAll()-main]释放了锁.
线程[awaitNanos(long)-Thread-1]被唤醒...
线程[awaitNanos(long)-Thread-1]释放了锁.
线程[awaitUninterruptibly()-Thread-4]被唤醒...
线程[awaitUninterruptibly()-Thread-4]释放了锁.
线程[await()-Thread-0]被唤醒...
线程[await()-Thread-0]释放了锁.
线程[await(long,TimeUnit)-Thread-2]被唤醒...
线程[await(long,TimeUnit)-Thread-2]释放了锁.
线程[awaitUntil(deadline)-Thread-3]被唤醒...
线程[awaitUntil(deadline)-Thread-3]释放了锁.

测试结果与预测一致。

5.总结

下面对上述的7个方法进行一句话总结:

  • await():等待,直到被唤醒或被中断
  • awaitUninterruptibly():等待,直到被唤醒中断无效
  • awaitNanos(long nanosTimeout):限定的纳秒时间内等待,直到被唤醒、被中断或限定时间超时
  • await(long time, TimeUnit unit):限定的时间内等待,直到被唤醒、被中断或限定时间超时
  • awaitUntil(Date deadline):指定的截止时间等待,直到被唤醒、被中断或截止时间过去
  • signal():唤醒一个线程。
  • signalAll():唤醒所有线程。

 

posted @ 2021-08-24 16:25  姚春辉  阅读(95)  评论(0编辑  收藏  举报