为了支持多线程之间的协作,JDK提供了两个非常重要的接口线程等待wait()方法和通知notify()方法。这两个方法并不是在Thread类中的,而是输出Object类,这也意味着任何对象都可以调用这两个方法。
那wait()和nofity()是如何工作的呢?如果 一个线程调用了object.wait(),那么它就会进入object对象的等待队列。这个等待队列中,可能会有多个线程,因为系统运行多个线程同时等待某一个对象。当object.nofity()被调用时,它就会从这个等待队列中,随机选择一个线程,(也不是优先通知优先级比较高的线程)并将期唤醒。这里希望大家注意的是,这个选择是不公平的,并不是先等待的线程会优先被选择,这个选择完全是随机的。
除了nofity()方法外,Obect对象还有一个类似的notifyAll()方法,它和notify()的功能基本一致,但不同的是,它会唤醒在这个等待队列所有等待的线程,而不是随机选择一个。这里要注意notifyAll唤醒的是notify之前wait的线程,对于notify之后的wait线程是没有效果的。
这里还需要强调一点,wait()方法并不是可以随便调用的,它必须包含在对应的synchronzied语句中,无论是wait()或者notify()都需要首先获得目标对象的一个监视器。
当需要调用以上的方法的时候,一定要对竞争资源进行加锁,如果不加锁的话,则会报 IllegalMonitorStateException 异常。
假设有三个线程执行了obj.wait( ),那么obj.notifyAll( )则能全部唤醒tread1,thread2,thread3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,tread1,thread2,thread3只有一个有机会获得锁继续执行,例如tread1,其余的需要等待thread1释放obj锁之后才能继续执行。
当调用obj.notify/notifyAll后,调用线程依旧持有obj锁,因此,thread1,thread2,thread3虽被唤醒,但是仍无法获得obj锁。直到调用线程退出synchronized块,释放obj锁后,thread1,thread2,thread3中的一个才有机会获得锁继续执行