wait()
当一个线程调用一个共享变量的 wait()方法时,该调用线程会被阻塞挂起,直到发生下面几件事情之一才返回:
(1)其他线程调用了该共享对象的notify()或者notifyAll()方法;
(2)其他线程调用了该线程的interrupt()方法,该线程抛出InterruptedException异常返回。
另外需要注意的是,如果调用wait()方法的线程没有事先获取该对象的监视器锁,则调用 wait()方法时调用线程会抛出IllegalMonitorStateException异常。
获取一个共享变量的监视器锁有以下两种常用方法:
(1)执行synchronized 同步代码块时,使用该共享变量作为参数。
(2)调用该共享变量的方法,并且该方法使用了synchronized修饰。
另外需要注意的是,一个线程可以从挂起状态变为可以运行状态(也就是被唤醒),即使该线程没有被其他线程调用notify()、notifyAll()方法进行通知,或者被中断,或者等待超时,这就是所谓的虚假唤醒。
另外需要注意的是,当前线程调用共享变量的 wait()方法后只会释放当前共享变量上的锁,如果当前线程还持有其他共享变量的锁,则这些锁是不会被释放的。
package thread.wait;
public class WaitTest {
private static volatile Object resourceA = new Object () ;
private static volatile Object resourceB = new Object ();
public static void main(String[] args) throws InterruptedException {
Thread threadA = new Thread (new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
synchronized (resourceA) {
System.out.println("threadA get resourceA lock");
synchronized (resourceB) {
System.out.println("threadA get resourceB lock" ) ;
System.out.println("threadA release resourceA lock");
resourceA .wait() ;
}
}
}catch (InterruptedException e) {
e.printStackTrace() ;
}
}
});
Thread threadB = new Thread (new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread .sleep(1000) ;
synchronized (resourceA) {
System.out.println("threadB get resourceA lock");
synchronized (resourceB) {
System.out.println("threadB get resourceB lock" ) ;
System.out.println("threadB release resourceA lock");
resourceA .wait() ;
}
}
}catch (InterruptedException e) {
e.printStackTrace() ;
}
}
});
//启动线程
threadA.start() ;
threadB.start() ;
//等待两个线程结束
threadA.join() ;
threadB.join() ;
}
}
debug可以看到 走到下边40行不再往下走,说明resourceB还未被释放
wait(long timeout)
该方法相比 wait()方法多了一个超时参数,它的不同之处在于,如果一个线程调用共享对象的该方法挂起后,没有在指定的timeout ms时间内被其他线程调用该共享变量的notify()或者notifyAll()方法唤醒,那么该方法还是会因为超时而返回。如果将timeout设置为0则和 wait方法效果一样,因为在 wait方法内部就是调用了wait(O)。需要注意的是,如果在调用该函数时,传递了一个负的timeout则会抛出IlegalArgumentException异常。
wait(long timeout, int nanos)
在其内部调用的是wait(long timeout)函数,如下代码只有在nanos>0时才使参数timeout递增1。