3.1等待和通知API(Wait-and-Notify API Tour)

来源:互联网 发布:小米电视软件推荐 编辑:程序博客网 时间:2024/06/01 07:13

va.lang.Object类提供了一个等待和通知API,其中包含了三个wait()方法,一个notify()方法和一个notifyAll()方法。wait()方法等待的状态是存在的;notify()和notifyAll()方法通知等待线程,只要这个状态存在。

        void wait():导致当前线程处于等待直到其它线程执行notify()或notifyAll()方法给这个对象,或其它线程在等待期间打断当前的线程。

        void wait(long timeout): 导致当前线程处于等待直到其它线程执行notify()或notifyAll()方法给这个对象,或指定时间以毫秒计算(确定超时时间),或其它线程在等待期间打断了当前的线程。如果timeout是不合法的,那么将会抛出java.lang.IllegaArgumentException的异常。

        void wait(long time,int nanos):  导致当前线程处于等待直到其它线程执行notify()或notifyAll()方法给这个对象,或指定时间以毫秒计算(确定超时时间),通过纳秒来进行累加(确定纳秒时间),或其它线程在等待期间打断了当前的线程。当timeout不合法,nanos不合法,或nanos大于999999,那么将会抛出IllegaArgummentException异常。

        void notify():唤醒一个在对象监测器中等待的单一线程。如果有多个线程在等待这个对象,那么其中一个会被唤醒。这个选择是任意的和出现应用自由选择。被唤醒的线程不会继续执行,而是直到当前线程放弃这个对象的锁。唤醒线程将以通常的方式与任何可能正在积极竞争在该对象上同步的线程竞争;例如,唤醒线程在锁定此对象的下一个线程中不享有可靠的特权或劣势。

        void notifyAll():唤醒所有在这个对象监测器等待的线程。被唤醒的线程不会继续执行,而是直到当前线程放弃这个对象的锁。唤醒线程将以通常的方式与任何可能正在积极竞争在该对象上同步的线程竞争;例如,唤醒线程在锁定此对象的下一个线程中不享有可靠的特权或劣势。

     在当前的线程正在等待唤醒之前被任何线程打断当前线程,那么这三个线程都会抛出java.lang.InterptedException异常。当这个异常出现,就可以说明当前线程状态是打断状态。

       Note  一个线程释放监测器连接对象的权力,它有wait()方法就会被调用。

这个API影响着一个对象的队列情况,这个数据结构存储着(存在)线程等待的状态。这个等待线程就是我们所知道的等待集合(wait set).因为队列状态被绑定到一个对象的锁,上面的五个方法必须在一个同步上下文中请求(当前线程必须是自己的对象监测器);其它的情况就是会抛出java.lang.IllegaMonitorStateException的异常。

下面的代码/伪代码片断证明wait()方法:

synchronized(obj){while (<condition does not hold>)obj.wait();// Perform an action that's appropriate to condition.} 

这个wait()方法被请求是在一个同步阻塞的内部,这个同步在与wait()请求的相同对象obj。因为存在虚假唤醒(spurious wakeups(一个线程唤醒没有被通知、打断或超时)),wait()方法在一个while的循环中被调用,当这个状态总是不能被持有时就会重复执行wait()方法。while循环退出后,条件存在,并且可以执行与该条件相关的动作。

       Caution 不要在循环外部调用wait()方法。循环测试状态在之前或之后请求wait()方法。在请求wait()方法之前要确定测试状态是活跃的。如果测试状态不存在,和如果条件成立和notify()在wait()方法之前被请求,等待线程永远不会被唤醒。之后请求wait()的方法重新测试这个状态,确保其安全性。如果测试没有出现,和之后通过wait()方法唤醒线程不成立(可能其它线程请求notify()方法时意外条件不成立),这个线程会继续破坏锁保护的不变量.

     下面代码片断证明了notify()方法,在前面的例子我们使用notify()通知等待的线程。

synchronized(obj){// Set the condition.obj.notify();}

otify()在临界区被请求,它控制着与临界区wait()方法的相同对象(obj)。notify()请求使用相同的对象引用。遵守这个的模式和你不会遇到困难。

       Note  这里一直在议论关于通知的方法,是notify()或notifyAll()哪个好。如果你在犹豫使用哪一个方法,在一个应用中如果只有仅仅两个线程,和其中任一线程等待都需要被其它线程唤醒,那么我将会使用notify()方法,其它情况,我们使用notifyAll()。