先来看一下Object类的wait()方法定义:实际上调用了一个带有参数的wait本地方法;
public final void wait() throws InterruptedException {
wait(0);
}
本地方法wait(long timeout),参数传递为0,表示当前线程一直等待直到被通知(notify/notifyAll);
public final native void wait(long timeout) throws InterruptedException;
看一下wait()方法的javadoc,如下片段;
* <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>
简译为:当前线程必须持有对象的锁。当前线程释放了持有的对象锁,一直等待到其他线程发出通知--通知等待这个对象锁的线程醒来。通知的方式是通过调用notify或notifyAll方法。当前线程然后等待重新获取对象锁,接着继续执行。
问题:如果直接调用wait方法会如何? 如: new Object().wait();
try {
new Object().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
很遗憾,会报错;
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
就是说当前线程如果没有获取对象锁,是无法直接调用wait()方法的。wait()方法的javadoc上已经写明:
* @throws IllegalMonitorStateException if the current thread is not
* the owner of the object's monitor.
那么wait()方法的本质是什么呢?
本质是当前线程释放持有的对象锁,当前线程进入等待队列,当然也让出了OS分配的CPU时间片,详细见这里;
本地方法wait(long timeout)有一段重要的javadoc,如下;调用wait方法会使当前线程进入一个等待集合里,"for this object"意思是【 如:obj.wait() 】 这些等待集合里的线程都是为了获取obj对象锁。"unlocks only this object"意思是仅仅释放obj的对象锁。
当前线程等待obj的对象锁,但是持有的其他对象锁是一直持有的。
* <p>
* Note that the {@code wait} method, as it places the current thread
* into the wait set for this object, unlocks only this object; any
* other objects on which the current thread may be synchronized remain
* locked while the thread waits.
* <p>
做个练习题吧,两个线程,一个打印奇数,一个打印偶数;保证打印出来的数字是连续的,如0,1,2,3,4....
public class TestWait {
private Object lock = new Object();
private int i = 0; //初始化为0:保证打印偶数线程先输出
private class PrinterRunnable implements Runnable {
private int remainder;
public PrinterRunnable(int remainder) {
this.remainder = remainder;
}
@Override
public void run() {
synchronized (lock) {
while (i < 100) {
if (i % 2 == remainder) {
System.out.println(Thread.currentThread().getName() + "__" + i);
i++;
}
lock.notifyAll();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public void runThreads() {
Thread printEvenThread = new Thread(new PrinterRunnable(0));
Thread printOddThread = new Thread(new PrinterRunnable(1));
printOddThread.start(); //让打印奇数线程先启动(实际上哪个线程先执行是未知的)
printEvenThread.start();
}
public static void main(String[] args) {
new TestWait().runThreads();
}
}
注意:notify/notifyAll() 要在wait方法之前执行,否则线程一直等待,得不到通知。
程序输出:
Thread-0__0
Thread-1__1
Thread-0__2
Thread-1__3
Thread-0__4
Thread-1__5
Thread-0__6
Thread-1__7
Thread-0__8
.
.
.
The End.