一.介绍
wait(),notify(),notifyAll()方法是位于Object类的方法,这三个方法调用的都是jvm的 native方法。
- wait()方法:持有该对象的线程处于等待,让出对象的控制权
- notify()方法:通知正在等待这个对象控制权的线程可以继续运行
- notifyAll()方法:通知所有等待这个对象控制权的线程继续运行
二.解释说明
wait方法,有三个重载的方法:
- wait()
- wait(long time)
- wait(long time1,int time2)
1.wait()方法
wait方法将当前线程置入休眠状态,知道被通知或中断为止,在调用wait()方法前,必须获取对象级别锁,因此它只能在同步方法和同步块调用。当调用wait()方法,当前线程释放锁,在从wait()方法返回前,线程与其他线程竞争重新获得锁。
2.notify()方法
该方法也要在同步方法和同步块中调用,在调用前必须获得对象级别锁,没有则抛出异常。
该方法用来通知那些等待该对象的对象锁的其他线程,如果有多个线程等待,则挑选出一个其中出于wait状态的线程来发出通知,并使得它获取对象锁。(执行notify方法后,当前线程并不会马上释放该对象锁,要等到程序退出synchronized代码块后,当前线程才可以释放对象锁,处于wait状态的线程才可以获取该对象锁)
下面举个例子:
public class TestWatiNotify {
public static Object obj=new Object();
public static void main(String[] args){
Thread1 t1=new Thread1();
t1.setName("线程1");
Thread2 t2=new Thread2();
t2.setName("线程2");
t1.start();
/* try {
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}*/
t2.start();
}
static class Thread1 extends Thread{
@Override
public void run(){
synchronized (obj){
System.out.println("调用wait方法前");
try{
obj.wait();
}catch (Exception e){
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"获取到锁");
}
}
}
static class Thread2 extends Thread{
@Override
public void run(){
synchronized (obj){
obj.notify();
System.out.println("线程"+Thread.currentThread().getName()+"调用了notify方法");
}
System.out.println("线程"+Thread.currentThread().getName()+"释放了该锁");
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"结束");
}
}
}
执行完上述代码,出现下面的结果:
调用wait方法前
线程线程2调用了notify方法
线程线程2释放了该锁
线程线程1获取到锁
线程线程2结束
分析一下结果我们发现,首先是线程1获取了对象锁,然后执行了wait()方法,所以释放了该对象锁,线程2获取了对象锁,它调用了notify()方法,在执行完当前线程的同步块后,线程1获取到对象锁,继续执行线程1同步块中wait方法之后的代码,同时线程2也在同步块后面的代码。我们发现,线程在唤醒等待该对象的其他线程,并释放掉对象锁的时候,这时候对象出于空闲状态,如果有多个出于等待的线程,那么它们会竞争该对象锁,但是不影响没有加该对象锁的线程执行。
3.notifyAll()方法
与notify()方法工作原理差不多,有一些小的差异:
notifyAll使所有原来在该对象上wait的线程退出wait状态(但并非全部获取对象锁,它们会竞争,只会有一个线程获取该对象锁),在notifyAll线程退出当前的synchronized同步块后,才参与竞争该对象锁,如果有一个线程获取到该对象锁,它会继续执行,直到执行完同步块释放对象锁,其他的被唤醒的线程将继续竞争对象锁,一直进行下去,直到所有被唤醒的线程都执行完毕。