5.线程间通信

wait和notify方法详解

wait

wait和notify方法不是Thread中的方法, 而是Object中的方法。

  • public final void wait() throws InterruptedException

  • public final void wait(long timeout) InterruptedException

  • public final void wati(long timeout, int nanos) InterruptedException

  • [ ] wait方法的这三个重载方法都调用wait(long timeout) 这个方法 wai()方法相当于wait(0), 0代表永不过时。

  • [ ] Object的wait(long timeout) 方法会导致当前线程进入阻塞, 直到有其他线程 调用了Object的notify或者notifyAll方法,才能将其唤醒,或者阻塞在达到了 timeout时间自动唤醒。

  • [ ] wait 方法必须拥有该对象的monitor, 也就是wait 方法必须在同频方法中使用。

  • [ ] 当前线程执行了该 对象的wait方法后, 将会放弃对该monit的所有权且进入与该对象关联的wait set中, 也就是说一旦线程执行了某个Object的wait方法之后, 它就会释放对该对象monitor的所有权, 其他线程也地有机会继续争抢该monitor的所有权。

notify

  • public final native void notify()
  • [ ] 唤醒单个正在执行该对象wait方法的线程
  • [ ] 如果有某个线程由于执行该 对象的wait方法而进入阻塞则会被唤醒, 如果没有则忽略。
  • [ ] 被唤醒的线程需要重新获取对该对象所关联的monitor的lock才能继续运行。

关于wait和notify的注意事项

  • wait方法是可中断方法, 这也意味着,当前线程一旦调用了wait方法进行阻塞状态, 其它线程是可以使用interrupt方法将其打断的;
  • 线程执行了某个对象的wait方法以后, 会加入与之对应的wait set中,每一个对象的monitor都有一个与之关联的wati set
  • 当线程进入wati set之后, notif方法可以将其唤醒, 也就从wati set 弹出, 同时中断wait中的线程也会将其唤醒。
  • 必须在同步方法中使用wait和notify方法, 因为执行wait和notify的前提条件是必须持有同步方法的monitor的所有权。
  • 同步代码的monitor必须与执行 wait和notify方法的对象一致, 简单地说就是用哪个对象的monitor进行同频, 就只能用哪个对象进行wait和notify操作。

wait 和 sleep

wait和sleep方法都可以使当前线程进入阻塞状态, 两者的区别是:

  • wait 和 sleep方法都可以使线程进入阻塞状态
  • wait 和 sleep方法都是可中断方法, 被中断后都会收到中断异常
  • wait是Object的方法, 而sleep是Thread特有的方法
  • wait方法的执行必须在同步方法中进行, 而sleep不需要
  • 线程在同步方法中执行sleep方法时, 并不会释放monitor锁, 而wait方法则会释放monitor锁
  • sleep方法短暂休眠之后会主动退出阻塞, 而wait方法(没有指定wait时间)则需要被其他线程中断后才能退出阻塞。