【Object类中的wait()方法和notify()方法】
wait():
public final void wait(long timeout) throws InterruptedException
参数:等待的时间,可选,不填则默认为0。
说明:
1>使线程主动释放对象锁,并进入等待状态,直到它被其他线程通过notify()或notifyAll唤醒或者超过指定的等待时间。
2>在调用wait方法前,线程必须获得该对象的对象锁,即:只能在同步方法或同步代码块中调用wait方法,如果当前线程不是锁的持有者,将抛出一个IllegalMonitorStateException异常(是RuntimeException的子类,故不需要捕获)。
3>wait方法执行完成后,该线程立即释放持有的对象锁(注:不是等到退出synchronized代码块后才释放)。
4>this method should always be used in a loop:
synchronized (obj) {
// 不满足条件时等待。
while (condition does not hold) {
obj.wait(); // 注:一般会有其它的线程当条件满足后调用notify方法
}
// 满足条件时执行execute方法。
execute(); // 注:使用while循环保证了这行代码始终是在满足条件下被执行的!
}
举例:
阶段1)A线程执行该代码块时,发现不满足条件condition,则A线程进入等待状态,并释放对象锁,
阶段2)B线程执行某些代码后,满足了条件condition,然后调用notify()方法并释放了对象锁,
阶段3)如果此时C线程获得了该对象锁,并执行了某些代码导致又不满足条件condition了,当C线程释放该对象锁后,
阶段4)A线程才获得了该对象锁,并执行wait()方法后面的代码。如果不使用while循环,而是使用if语句来判断(如下),则会导致execute()方法在不满足条件的情况下被执行了!
synchronized (obj) {
if (condition does not hold) {
obj.wait();
}
execute();
}
解析:
执行execute方法的情况:
1)执行代码块时,条件已满足,则不会调用wait方法,直接执行execute方法。
2)执行代码块时,条件不满足,则调用wait方法,等到被唤醒后(注:被唤醒后条件可能发生变化),再去执行execute方法。
使用while循环:保证了在调用wait方法前(阶段1)和在被唤醒后(阶段4)都去检查条件是否满足,如果满足则执行excute方法,如果不满足则继续等待。
使用if语句:只保证了在调用wait方法前(阶段1)去检查条件是否满足,并没有在线程被唤醒后去检查是否满足条件。如果发生了阶段3的情况,则execute方法将在不满足条件的情况下执行了。
notify():
public final void notify()
说明:
1>随机选择一个在该对象上调用wait方法的线程,赋予其对象锁,解除其阻塞状态。
2>在执行notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程退出synchronized方法或synchronized代码块后,当前线程才会释放锁,此时wait状态的线程才可以获取该对象锁,并继续执行synchronized代码块中wait()方法后面的代码。
notifyAll():
public final void notifyAll()
说明:唤醒在该对象上调用wait方法等待的所有线程。
说明:wait()、notify()、notifyAll()这三个方法:
1)在调用方法前,线程必须获得该对象的对象锁,如果当前线程不是锁的持有者,方法将抛出一个IllegalMonitorStateException异常(是RuntimeException的子类,故不需要捕获)。
2)只能在非静态同步方法或非静态同步代码块内调用,而且必须由锁对象来调用方法:
1>这3个方法都是非静态方法,且这3个方法必须由锁对象调用,所以我们不能在静态同步方法和静态代码块中调用(静态同步方法的锁是类的Class锁)。
2>synchronized修饰的非静态方法:因为this就是锁对象,所以可以在同步方法中调用这三个方法(可以将this省略)。
3>synchronized修饰的非静态同步代码块:必须使用锁对象来调用这三个方法。
3)由于wait,notify和notifyAll都是锁级别的操作,而锁属于对象,故把他们定义在Object类中,而不是定义在Thread类中。
来源:oschina
链接:https://my.oschina.net/u/1399755/blog/1811431