乐趣区

Java高性能编程实战-线程通信

要想实现多个线程之间的协同,如: 线程执行先后顺序、获取某个线程执行的结果等等。
涉及到线程之间相互通信,分为下面四类:

1 文件共享

2 网络共享

socket 编程问题, 非本文重点, 不再赘述

3 共享变量

4 线程协作 – JDK API

细分为: suspend/resume、wait/notify、park/unpark

JDK 中对于需要多线程协作完成某一任务的场景,提供了对应 API 支持。
多线程协作的典型场景是: 生产者 - 消费者模型。(线程阻塞、线程唤醒)

示例: 线程 1 去买包子,没有包子,则不再执行。线程 - 2 生产出包子,通知线程 - 1 继续执行。

4.1 API – 被弃用的 suspend 和 resume

作用: 调用 suspend 挂起目标线程,通过 resume 可以恢复线程执行

被弃用的主要原因是,容易写出

死锁代码

  • 同步代码中使用


  • 先后顺序:suspend 比 resume 后执行


所以用 wait/notify 和 park/unpark 机制对它进行替代

4.2 wait/notify

这些方法只能由 同一对象锁 的持有者线程调用,也就是写在同步块里面,否则会抛 IllegalMonitorStateException

wait 方法导致当前线程等待,加入该对象的等待集合中,并且 放弃当前持有的对象锁

notify/notifyAll 方法唤醒一个 或所有正在等待这个对象锁的线程。

虽然 wait 会自动解锁,但是 对顺序有要求 ,如果在 notify 被调用之后,才开始 wait 方法的调用,线程会永远处于WAITING 状态。

  • 正常使用

  • 死锁


  • 小结

4.3 park/unpark

线程调用 park 则等待“许可”,unpark 方法为指定线程提供“许可(permit)”。

不要求 park 和 unpark 方法的调用顺序

多次调用 unpark 之后,再调用 park, 线程会直接运行。
但不会叠加 ,即连续多次调用 park 方法,第一次会拿到“许可”直接运行,后续调
用会进入等待。

  • 正常
  • 死锁

5 伪唤醒

之前代码中用 if 语句来判断,是否进入等待状态,是错误的!

官方建议 应该在循环中检查等待条件 ,原因是处于等待状态的线程可能会收到 ** 错误警报和伪
唤醒 **,如果不在循环中检查等待条件,程序就会在没有满足结束条件的情况下退出。

伪唤醒是指线程并非因为 notify、notifyall、unpark 等 api 调用而唤醒,是更底层原因导致的。

6 总结

涉及很多 JDK 多线程开发工具类及其底层实现的原理

退出移动版