要想实现多个线程之间的协同, 如: 线程执行先后顺序, 获取某个线程执行的结果等等.
涉及到线程之间相互通信, 分为下面四类:
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 多线程开发工具类及其底层实现的原理
来源: http://www.jianshu.com/p/2eec466b64c5