Javaマルチスレッド状態のソースコード分析

package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.Date;

/**
 * Condition将对象monitor方法(wait, notify,notifyAll)分解成不同的对象,
 * 通过将它们与任意的锁实现结合使用,从而产生每个对象拥有多个等待集的效果。
 * 如果锁代替了synchronized方法和语句的使用,那么Condition就代替了Object监视方法的使用。
 *
 * <p>条件(也称为条件队列或条件变量)为一个线程提供了暂停执行(“等待”)的方法,
 * 直到另一个线程通知某个状态条件现在可能为真。由于对共享状态信息的访问发生在不同的线程中,因此必须对其进行保护,因此某种形式的锁与条件相关联。
 * 等待条件提供的关键属性是,它会自动释放相关的锁并挂起当前线程,就像Object.wait一样。
 *
 * <p>条件实例在本质上与锁绑定。
 * 要获取特定Lock实例的条件实例,请使用它的newCondition()方法。
 *
 * <p>举个例子,假设我们有一个支持put和take方法的有界缓冲区。
 * 如果尝试在空缓冲区上执行take操作,那么线程将阻塞,直到有一个条目可用;
 * 如果试图在全缓冲区上执行put操作,那么线程将阻塞,直到有空间可用为止。
 * 我们希望将put线程和take线程放在单独的等待集中,这样我们就可以使用优化的方法,
 * 当缓冲区中有项目或空间可用时,只通知单个线程。这可以通过使用两个条件实例来实现。
 * 
 * <pre>
 * class BoundedBuffer {
 *   <b>final Lock lock = new ReentrantLock();</b>
 *   final Condition notFull  = <b>lock.newCondition(); </b>
 *   final Condition notEmpty = <b>lock.newCondition(); </b>
 *
 *   final Object[] items = new Object[100];
 *   int putptr, takeptr, count;
 *
 *   public void put(Object x) throws InterruptedException {
 *     <b>lock.lock();
 *     try {</b>
 *       while (count == items.length)
 *         <b>notFull.await();</b>
 *       items[putptr] = x;
 *       if (++putptr == items.length) putptr = 0;
 *       ++count;
 *       <b>notEmpty.signal();</b>
 *     <b>} finally {
 *       lock.unlock();
 *     }</b>
 *   }
 *
 *   public Object take() throws InterruptedException {
 *     <b>lock.lock();
 *     try {</b>
 *       while (count == 0)
 *         <b>notEmpty.await();</b>
 *       Object x = items[takeptr];
 *       if (++takeptr == items.length) takeptr = 0;
 *       --count;
 *       <b>notFull.signal();</b>
 *       return x;
 *     <b>} finally {
 *       lock.unlock();
 *     }</b>
 *   }
 * }
 * </pre>
 *
 * (java.util.concurrent.ArrayBlockingQueue类提供了这个功能,所以没有理由实现这个示例使用类。)
 *
 * <p>条件实现可以提供与对象监控方法不同的行为和语义,
 * 比如保证通知的顺序,或者在执行通知时不需要持有锁。
 * 如果实现提供了这样专门化的语义,那么实现必须记录这些语义。
 *
 * <p>请注意,条件实例只是普通对象,它们本身可以用作同步语句中的目标,并且可以调用它们自己的监视器等待和通知方法。
 * 获取条件实例的monitor锁,或使用其monitor方法,与获取与该条件相关的锁或使用其等待和信号传递方法没有指定的关系。
 * 为了避免混淆,建议您永远不要以这种方式使用条件实例,除非在它们自己的实现中。
 *
 * <p>除非有特别说明,否则传递任何参数的空值都会导致抛出NullPointerException。
 *
 * <h3>Implementation Considerations</h3>
 *
 * <p>当等待一个条件时,通常允许发生“伪唤醒”,这是对底层平台语义的让步。
 * 这对大多数应用程序几乎没有实际影响,因为应该始终在循环中等待一个条件,测试正在等待的状态谓词。
 * 一个实现是免费的,以消除虚假的唤醒的可能性,但它建议应用程序程序员总是假设它们可以发生,所以总是在循环中等待。
 *
 * <p>条件等待的三种形式(可中断、不可中断和定时)在某些平台上实现的便捷性和性能特征上可能有所不同。
 * 特别是,可能很难提供这些特性和维护特定的语义,比如排序保证。
 * 此外,在所有平台上,中断线程的实际挂起可能并不总是可行的。
 *
 * <p>因此,实现不需要为所有三种形式的等待定义完全相同的保证或语义,也不需要支持中断线程的实际挂起。
 *
 * <p>一个实现需要清楚地记录每个等待方法提供的语义和保证,并且当一个实现支持中断线程挂起,那么它必须遵守这个接口中定义的中断语义。
 *
 * <p>由于中断通常意味着取消,并且对中断的检查经常是不频繁的,一个实现可以更倾向于响应中断而不是正常的方法返回。
 * 这是正确的,即使它可以证明中断发生在另一个可能已经解除线程阻塞的操作之后。
 * 实现应该记录这种行为。
 *
 * @since 1.5
 * @author Doug Lea
 */
public interface Condition {

    /**
     * 使当前线程等待,直到发出信号或被中断。
     *
     * <p>与此条件相关的锁被原子释放,当前线程在线程调度中被禁用并处于休眠状态,直到以下四种情况之一发生:
     * <ul>
     * <li>一些其他的线程调用这个条件的signal方法,并且当前的线程碰巧被选择为被唤醒的线程;或
     * <li>一些其他线程在这种情况下调用signalAll方法;或
     * <li>一些其他线程中断当前线程,并支持中断线程暂停;或
     * <li>“假醒”发生。
     * </ul>
     *
     * <p>在所有情况下,在此方法可以返回当前线程之前,必须获取与此条件相关联的锁。当线程返回时,它保证持有这个锁。
     *
     * <p>如果当前线程:
     * <ul>
     * <li>在进入该方法时设置中断状态;或
     * <li>在等待时被中断,并且支持中断线程悬挂,
     * </ul>
     * 然后抛出InterruptedException,并清除当前线程的中断状态。在第一种情况下,没有指定是否在锁释放之前发生中断测试。
     *
     * <p><b>Implementation Considerations</b>
     *
     * <p>当调用此方法时,假定当前线程持有与此条件相关联的锁。
     * 如果是这样,则由实现决定,如果不是,则如何响应。
     * 通常,会抛出一个异常(如IllegalMonitorStateException),并且实现必须记录这个事实。
     *
     * <p>实现可以支持响应中断,而不是响应signal的通常返回。
     * 在这种情况下,实现必须确保signal被重定向到另一个等待线程(如果有的话)。
     *
     * @throws InterruptedException if the current thread is interrupted
     *         (and interruption of thread suspension is supported)
     */
    void await() throws InterruptedException;

    /**
     * 使当前线程等待,直到发出信号。
     *
     * <p>与此条件相关的锁被原子释放,当前线程在线程调度中被禁用并处于休眠状态,直到以下三种情况之一发生:
     * <ul>
     * <li>一些其他的线程调用这个条件的信号方法,并且当前的线程碰巧被选择为被唤醒的线程;或
     * <li>一些其他线程在这种情况下调用signalAll方法;或
     * <li>“假醒”发生。
     * </ul>
     *
     * <p>在所有情况下,在此方法可以返回当前线程之前,必须获取与此条件相关联的锁。当线程返回时,它保证持有这个锁。
     *
     * <p>如果当前线程的中断状态在它进入这个方法时被设置,或者它在等待时被中断,它将继续等待直到有信号。
     * 当它最终从这个方法返回时,它的中断状态仍然会被设置。
     *
     * <p><b>Implementation Considerations</b>
     *
     * <p>当调用此方法时,假定当前线程持有与此条件相关联的锁。
     * 如果是这样,则由实现决定,如果不是,则如何响应。
     * 通常,会抛出一个异常(如IllegalMonitorStateException),并且实现必须记录这个事实。
     */
    void awaitUninterruptibly();

    /**
     * 使当前线程等待,直到发出信号或中断,或者指定的等待时间过去。
     *
     * <p>与此条件相关的锁被原子释放,当前线程在线程调度中被禁用并处于休眠状态,直到以下三种情况之一发生:
     * <ul>
     * <li>一些其他的线程调用这个条件的信号方法,并且当前的线程碰巧被选择为被唤醒的线程;或
     * <li>一些其他线程在这种情况下调用signalAll方法;或
     * <li>一些其他线程中断当前线程,并支持中断线程暂停;或
     * <li>指定的等待时间已经过去;或
     * <li>“假醒”发生。
     * </ul>
     *
     * <p>在所有情况下,在此方法可以返回当前线程之前,必须获取与此条件相关联的锁。当线程返回时,它保证持有这个锁。
     *
     * <p>如果当前线程:
     * <ul>
     * <li>在进入该方法时设置中断状态;或
     * <li>在等待时被中断,并且支持中断线程悬挂,
     * </ul>
     * 然后抛出InterruptedException,并清除当前线程的中断状态。
     * 在第一种情况下,没有指定是否在锁释放之前发生中断测试。
     *
     * <p>该方法在返回时根据提供的nanosTimeout,返回剩余等待的纳秒数估计数,如果超时则返回小于或等于零的值。
     * 当等待返回但awaited条件仍然不成立时,此值可用于确定是否重新等待以及重新等待多长时间。这种方法的典型用法如下:
     *
     *  <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>设计注意:该方法需要一个纳秒参数,以避免报告剩余时间时出现截断错误。
     * 这样的精度损失将使程序员很难确保在发生重新等待时,总等待时间不会系统地小于指定的时间。
     *
     * <p><b>Implementation Considerations</b>
     *
     * <p>当调用此方法时,假定当前线程持有与此条件相关联的锁。
     * 如果是这样,则由实现决定,如果不是,则如何响应。
     * 通常,会抛出一个异常(如IllegalMonitorStateException),并且实现必须记录这个事实。
     *
     * <p>一个实现可以更倾向于响应一个中断,而不是响应一个信号的正常方法返回,或者更倾向于指示指定的等待时间。
     * 在任何一种情况下,实现都必须确保信号被重定向到另一个等待线程(如果有的话)。
     *
     * @param nanosTimeout the maximum time to wait, in nanoseconds
     * @return an estimate of the {@code nanosTimeout} value minus
     *         the time spent waiting upon return from this method.
     *         A positive value may be used as the argument to a
     *         subsequent call to this method to finish waiting out
     *         the desired time.  A value less than or equal to zero
     *         indicates that no time remains.
     * @throws InterruptedException if the current thread is interrupted
     *         (and interruption of thread suspension is supported)
     */
    long awaitNanos(long nanosTimeout) throws InterruptedException;

    /**
     * 使当前线程等待,直到发出信号或中断,或者指定的等待时间过去。这个方法在行为上相当于:
     *  <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>
     *
     * <p><b>Implementation Considerations</b>
     *
     * <p>The current thread is assumed to hold the lock associated with this
     * {@code Condition} when this method is called.
     * It is up to the implementation to determine if this is
     * the case and if not, how to respond. Typically, an exception will be
     * thrown (such as {@link IllegalMonitorStateException}) and the
     * implementation must document that fact.
     *
     * <p>An implementation can favor responding to an interrupt over normal
     * method return in response to a signal, or over indicating the passing
     * of the specified deadline. In either case the implementation
     * must ensure that the signal is redirected to another waiting thread, if
     * there is one.
     *
     * @param deadline the absolute time to wait until
     * @return {@code false} if the deadline has elapsed upon return, else
     *         {@code true}
     * @throws InterruptedException if the current thread is interrupted
     *         (and interruption of thread suspension is supported)
     */
    boolean awaitUntil(Date deadline) throws InterruptedException;

    /**
     * 唤醒一个等待的线程。
     *
     * <p>如果有任何线程正在等待这个条件,那么将选择一个线程进行唤醒。
     * 然后,该线程必须在从await返回之前重新获得锁。
     *
     * <p><b>Implementation Considerations</b>
     *
     * <p>实现可能(通常)要求当前线程在调用此方法时持有与此条件相关的锁。
     * 实现必须记录这个前置条件以及在没有持有锁的情况下采取的任何操作。
     * 通常,会抛出像IllegalMonitorStateException这样的异常。
     */
    void signal();

    /**
     * 唤醒所有等待的线程。
     *
     * <p>如果有线程在等待这个条件,那么它们都会被唤醒。每个线程在从await返回之前必须重新获取锁。
     *
     * <p><b>Implementation Considerations</b>
     *
     * <p>实现可能(通常)要求当前线程在调用此方法时持有与此条件相关的锁。
     * 实现必须记录这个前置条件以及在没有持有锁的情况下采取的任何操作。
     * 通常,会抛出像IllegalMonitorStateException这样的异常。
     */
    void signalAll();
}

 

おすすめ

転載: blog.csdn.net/xushiyu1996818/article/details/112846449
おすすめ