写于:2019-12-01
一、线程通讯概念
与网络通讯等进程间通信方式不一样,线程间通讯又称为进程内通信,多个线程实现互斥访问共享资源时会互相发送信号或等待信号,比如线程等待数据到来的通知,线程收到变量改变的信号灯。
二、JAVA 原生 API
1、Object.wait:阻塞当前线程
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阻塞的线程
通过 JDK DOC 说明能知道 notify 和 notifyAll 的区别。
- notify 只会唤醒 wait set 中休息的一个线程
- notifyAll 会唤醒 wait set 中休息的所有线程,多个线程仍需要争抢 monitor 的所有权。
如图: