写于:2019-12-01

一、线程通讯概念

与网络通讯等进程间通信方式不一样,线程间通讯又称为进程内通信,多个线程实现互斥访问共享资源时会互相发送信号或等待信号,比如线程等待数据到来的通知,线程收到变量改变的信号灯。

二、JAVA 原生 API

1、Object.wait:阻塞当前线程

01.png

wait 方法详细信息

  • a、上述三个重载 wait 方法,都表示将当前调用该方法的线程加入到 wait set 中。
    wait():等价于 wait(0) ,表示当前阻塞永不超时。
    wait(long) 和 wait(long ,int):表示阻塞当前线程一定时间,时间到了自动唤醒阻塞的线程。
  • b、被 wait 阻塞的线程,只有其他线程调用 Object.notify 或者 Object.notifyAll 时会被唤醒,或者阻塞时间到达 timeout 时间自动唤醒
  • c、wait 方法必须拥有该对象的 monitor ,也就是 wait 方法必须在同步方法中使用。
  • d、当前线程执行了该对象的 wait 方法之后,将会放弃对该 monitor 的所有权并进入与该对象关联的 wait set 中,也即是说一旦线程执行了某个 object 的 wait 方法之后,他就会释放该对象 monitor 的所有权,其他线程也有机会继续争抢该 monitor 的所有权。

小贴士:wati set 在虚拟机规范中存在一个 wait set 的概念,对于 wait set 的结构和规范 JDK 官方没有给出明确的定义,不同 JDK 厂家存在不同的差异,不管何种实现方式,都有如下特点: a、所有的对象都会有一个 wait set ,用来存放调用了该对象wait方法之后进入 block 状态的线程。 b、线程被 notify 之后,不一定立即得到执行 c、线程从 wait set 中被唤醒顺序不一定是 FIFO d、线程被唤醒之后需要重新获取锁 e、wait 方法之后线程进入到该对象 monitor 关联的 wait set 中,并释放 monitor 的所有权。

wait 方法使用注意事项

  • a、wait 方法是可中断方法,当线程调用 wait 进入阻塞状态时,能够通过其他线程使用 interrupt 方法进行打断。
    《interrupt 相关解释》
  • b、wait 方法必须在同步方法中使用,因为执行 wait 的前提条件是必须持有同步方法的 monitor 的所有权。
  • c、通过 notify 、notifyAll 或者中断 的方式能够唤醒 wait 中的线程。

2、Object.notify 和 Object.notifyAll:唤醒被wait阻塞的线程

02.png

通过 JDK DOC 说明能知道 notify 和 notifyAll 的区别。

  • notify 只会唤醒 wait set 中休息的一个线程
  • notifyAll 会唤醒 wait set 中休息的所有线程,多个线程仍需要争抢 monitor 的所有权。

如图:
03.png
04.png