Java的Object类包含了三个final方法,容许线程就资源的锁定状态进行通讯。这三个方法分别是:wait(),notify(),notifyAll(),今天来了解一下这三个方法。在任何对象上调用这些方法的当前线程应具备对象监视器(锁住了一个对象,就是得到对象相关联的监视器),不然会抛出java.lang.IllegalMonitorStateException异常。java
Object.wait有三种重载的实现,一个无限期等待任何其余线程地调用对象的notify或notifyAll方法来唤醒当前线程。 其余两个会使当前线程在等待特定的时间后进行唤醒。app
使得当前线程进程等待,直到另外一个线程在这个对象上调用了notify()方法或者notifyAll()方法。这个方法的行为,彻底等价于调用wait(0),能够看它的实现代码为:ide
public final void wait() throws InterruptedException { wait(0); }
当前的线程必须得到这个对象的监视器。线程释放了监视器的全部权,直到另外一个线程调用notify方法或者notifyAll方法,去唤醒在这个对象监视器上等待的其余线程。释放了监视器的全部权后,线程便进行等待,直到从新得到监视器的全部权并恢复执行。处于wait状态中的线程,可能被中断或虚假唤醒,因此这个方法应该老是在一个循环中使用:测试
synchronized (obj) { while (<condition does not hold>) obj.wait(); ... // Perform action appropriate to condition }
虚假唤醒指的是一些obj.wait()会在除了obj.notify()和obj.notifyAll()的其余状况被唤醒,而此时是不该该唤醒的,更详细的能够看Spurious_wakeup。
this
方法会抛出两种异常:spa
IllegalMonitorStateException:若是当前线程没有得到当前对象的监视器。操作系统
InterruptedException:若是某个线程在当前线程等待通知的时候,或是在等待通知以前中断了当前线程,当抛出这个异常时,当前线程的中断状态被清除。线程
该方法会使得当前进程进入wait状态直到另外一个线程调用notify/notifyAll,或是通过了指定的时间,线程将被唤醒。该方法会抛出异常:code
IllegalArgumentException:若是timeout是负数。orm
一样的,该方法会使得当前进程进入wait状态直到另外一个线程调用notify/notifyAll。它能够更加精细地控制等待的时间,以纳秒为单位测量的实时量由下式给出:1000000*timeout+nanos。除此以外,这个方法与wait(long)作相同的事情,特别的,wait(0,0)等价于wait(0)。除了其他两个wait方法会抛出的异常外,这个方法会抛出异常:
IllegalArgumentException:若是timeout是负数,或者nanos的范围不在0-999999之间时,抛出该异常。
notify方法只唤醒等待对象的一个线程,而且该线程开始执行。因此若是有多个线程在等待一个对象,这个方法只会唤醒其中的一个。线程的选择取决于线程管理的OS实现。
notifyAll方法唤醒等待对象的全部线程,但哪个将首先处理取决于操做系统的实现。
这些方法可用于实现生产者消费者问题,其中消费者线程正在等待队列中的对象,生产者线程将对象放入队列中并通知等待的线程。下面是一个多个线程工做在同一个对象上的例子,使用了wait,notify,notifyAll方法:
public class Message { private String msg; public Message(String str){ this.msg=str; } public String getMsg() { return msg; } public void setMsg(String str) { this.msg=str; } }
public class Notifier implements Runnable { private Message msg; public Notifier(Message msg) { this.msg = msg; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name+" started"); try { Thread.sleep(1000); synchronized (msg) { msg.setMsg(name+" Notifier work done"); msg.notify(); // msg.notifyAll(); } } catch (InterruptedException e) { e.printStackTrace(); } } }
public class Waiter implements Runnable{ private Message msg; public Waiter(Message m){ this.msg=m; } @Override public void run() { String name = Thread.currentThread().getName(); synchronized (msg) { try{ System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis()); msg.wait(); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis()); //process the message now System.out.println(name+" processed: "+msg.getMsg()); } } }
public class WaitNotifyTest { public static void main(String[] args) { Message msg = new Message("process it"); Waiter waiter = new Waiter(msg); new Thread(waiter,"waiter").start(); Waiter waiter1 = new Waiter(msg); new Thread(waiter1, "waiter1").start(); Notifier notifier = new Notifier(msg); new Thread(notifier, "notifier").start(); System.out.println("All the threads are started"); } }
输出:
waiter waiting to get notified at time:1516757290631 All the threads are started waiter1 waiting to get notified at time:1516757290632 notifier started waiter waiter thread got notified at time:1516757291632 waiter processed: notifier Notifier work done
能够看到两个线程在对象msg上进行等待,调用notify方法时,只有一个线程被唤醒,此时程序并无退出,由于还有一个线程在等待。
若是把notify方法改为notifyAll,运行结果为:
waiter waiting to get notified at time:1516757437164 waiter1 waiting to get notified at time:1516757437164 All the threads are started notifier started waiter1 waiter thread got notified at time:1516757438165 waiter1 processed: notifier Notifier work done waiter waiter thread got notified at time:1516757438165 waiter processed: notifier Notifier work done
能够看到两个线程都被唤醒了,程序也退出运行了。
(完)