美文网首页
Java中wait,notify,notifyAll分析

Java中wait,notify,notifyAll分析

作者: 老羊_肖恩 | 来源:发表于2018-01-10 14:49 被阅读31次

  wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。这三个方法最终调用的都是jvm级的native方法。针对不同的JVM,有不同的实现方式,但是工作原理都是一样的。
  如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。具体我们可以看源码。

wait方法

/**
     * Causes the current thread to wait until another thread invokes the
     * {@link java.lang.Object#notify()} method or the
     * {@link java.lang.Object#notifyAll()} method for this object.
     * In other words, this method behaves exactly as if it simply
     * performs the call {@code wait(0)}.
     * <p>
     * The current thread must own this object's monitor. The thread
     * releases ownership of this monitor and waits until another thread
     * notifies threads waiting on this object's monitor to wake up
     * either through a call to the {@code notify} method or the
     * {@code notifyAll} method. The thread then waits until it can
     * re-obtain ownership of the monitor and resumes execution.
     * <p>
     * As in the one argument version, interrupts and spurious wakeups are
     * possible, and this method should always be used in a loop:
     * <pre>
     *     synchronized (obj) {
     *         while (&lt;condition does not hold&gt;)
     *             obj.wait();
     *         ... // Perform action appropriate to condition
     *     }
     * </pre>
     * This method should only be called by a thread that is the owner
     * of this object's monitor. See the {@code notify} method for a
     * description of the ways in which a thread can become the owner of
     * a monitor.
     *
     * @throws  IllegalMonitorStateException  if the current thread is not
     *               the owner of the object's monitor.
     * @throws  InterruptedException if any thread interrupted the
     *             current thread before or while the current thread
     *             was waiting for a notification.  The <i>interrupted
     *             status</i> of the current thread is cleared when
     *             this exception is thrown.
     * @see        java.lang.Object#notify()
     * @see        java.lang.Object#notifyAll()
     */
    public final void wait() throws InterruptedException {
        wait(0);
    }

  wait()方法,默认调用了自己的wait(0)来实现。 wait方法会使当前线程放弃持有当前对象的monitor,直到其他线程调用了notify()notifyAll()方法。调用wait方法之前,当前线程必须持有该对象的monitor,一旦调用wait方法,当前线程会立即释放该对象的monitor并进入等待状态,直到其他线程通过notify或者notifyAll唤醒当前线程,当前线程会进入等锁状态,直到获取锁,该线程才能再次执行。该方法只有当前线程获取了对象的monitor之后才能执行,否则会抛出IllegalMonitorStateException异常。

/**
     * Causes the current thread to wait until either another thread invokes the
     * {@link java.lang.Object#notify()} method or the
     * {@link java.lang.Object#notifyAll()} method for this object, or a
     * specified amount of time has elapsed.
     * <p>
     * The current thread must own this object's monitor.
     * <p>
     *  其他忽略。。。。
     */
    public final native void wait(long timeout) throws InterruptedException;

  wait()wait(timeout)方法的一个特例,wait(timeout)方法允许当前线程在等待timeout(timeout不能为0,如果timeout为0,当前线程只能由notify或notifyAll唤醒)时间以后,自动被唤醒,即使没有其他线程调用当前对象的notify方法或notifyAll方法。与wait()方法一样,wait(timeout)方法只允许当前线程持有了对象的monitor之后才能执行,否则会抛出IllegalMonitorStateException异常。
  另外Object还提供了一种粒度更细的wait方法,代码如下所示。wait(timeout,nanos)方法与wait(timeout)类似,只是时间精度精确到纳秒。

/**
     * Causes the current thread to wait until another thread invokes the
     * {@link java.lang.Object#notify()} method or the
     * {@link java.lang.Object#notifyAll()} method for this object, or
     * some other thread interrupts the current thread, or a certain
     * amount of real time has elapsed.
     * <p>
     * This method is similar to the {@code wait} method of one
     * argument, but it allows finer control over the amount of time to
     * wait for a notification before giving up. The amount of real time,
     * measured in nanoseconds, is given by:
     * <blockquote>
     * <pre>
     * 1000000*timeout+nanos</pre></blockquote>
     * <p>
     * In all other respects, this method does the same thing as the
     * method {@link #wait(long)} of one argument. In particular,
     * {@code wait(0, 0)} means the same thing as {@code wait(0)}.
     * <p>
     * 其他省略。。。。。
     */
    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }
        if (nanos > 0) {
            timeout++;
        }
        wait(timeout);
    }

notify方法

  notify主要用于唤醒一个单独的等待获取当前对象monitor的线程。如果有不止一个线程在等待获取当前对象的monitor,那么其中只有一个线程会被选择出来唤醒,而这种选择在执行的时候是任意的。被唤醒的线程并不会立即得到执行,直到其获取了当前对象的monitor。
  该方法只有在线程获取了当前对象的monitor之后才能调用,否则将抛出IllegalMonitorStateException异常。因为一旦开始执行notify方法,线程会立即释放掉已经获取的当前对象的monitor。线程获取一个对象的monitor有三种方法:

  1. 执行该对象的synchronized实例方法。
  2. 执行该对象的synchronized代码块。
  3. 执行该对象的类中的静态方法。
    notify()代码如下。
/**
     * Wakes up a single thread that is waiting on this object's
     * monitor. If any threads are waiting on this object, one of them
     * is chosen to be awakened. The choice is arbitrary and occurs at
     * the discretion of the implementation. A thread waits on an object's
     * monitor by calling one of the {@code wait} methods.
     * <p>
     * The awakened thread will not be able to proceed until the current
     * thread relinquishes the lock on this object. The awakened thread will
     * compete in the usual manner with any other threads that might be
     * actively competing to synchronize on this object; for example, the
     * awakened thread enjoys no reliable privilege or disadvantage in being
     * the next thread to lock this object.
     * <p>
     * This method should only be called by a thread that is the owner
     * of this object's monitor. A thread becomes the owner of the
     * object's monitor in one of three ways:
     * <ul>
     * <li>By executing a synchronized instance method of that object.
     * <li>By executing the body of a {@code synchronized} statement
     *     that synchronizes on the object.
     * <li>For objects of type {@code Class,} by executing a
     *     synchronized static method of that class.
     * </ul>
     * <p>
     * Only one thread at a time can own an object's monitor.
     *
     * @throws  IllegalMonitorStateException  if the current thread is not
     *               the owner of this object's monitor.
     * @see        java.lang.Object#notifyAll()
     * @see        java.lang.Object#wait()
     */
    public final native void notify();

notifyAll方法

  notifyAll方法用于唤醒所有等待当前对象monitor的线程。与notify一样,唤醒的线程并不能立即得到执行,除非竞争到了当前对象的monitor。同样的,该方法只有在线程获取了当前对象的monitor之后才能调用,否则将抛出IllegalMonitorStateException异常。

/**
     * Wakes up all threads that are waiting on this object's monitor. A
     * thread waits on an object's monitor by calling one of the
     * {@code wait} methods.
     * <p>
     * The awakened threads will not be able to proceed until the current
     * thread relinquishes the lock on this object. The awakened threads
     * will compete in the usual manner with any other threads that might
     * be actively competing to synchronize on this object; for example,
     * the awakened threads enjoy no reliable privilege or disadvantage in
     * being the next thread to lock this object.
     * <p>
     * This method should only be called by a thread that is the owner
     * of this object's monitor. See the {@code notify} method for a
     * description of the ways in which a thread can become the owner of
     * a monitor.
     *
     * @throws  IllegalMonitorStateException  if the current thread is not
     *               the owner of this object's monitor.
     * @see        java.lang.Object#notify()
     * @see        java.lang.Object#wait()
     */
    public final native void notifyAll();

相关文章

网友评论

      本文标题:Java中wait,notify,notifyAll分析

      本文链接:https://www.haomeiwen.com/subject/zyznnxtx.html