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 (<condition does not hold>)
* 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有三种方法:
- 执行该对象的synchronized实例方法。
- 执行该对象的synchronized代码块。
- 执行该对象的类中的静态方法。
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();
网友评论