线程间通信和信令 - 章节
发信号的需要 - 小节
发信号的需要
线程还没有工作要做
需要在操作期间向线程提供额外的数据
ack
等待并释放互斥体(监视器)
实现生产者/消费者模式
演示BlockingQueue
生产者消费模式 - 小节
生产者/消费者模式
从一个或多个生产者发送到一个或多个消费者的消息
- 消费者使用消息
- 生产者发送它
消费者代表生产者进行这项工作
分离
允许将工作转移到灵活的工人数量
分离关注点——提高凝聚力
- 简化了杀伤人员地雷
- 使代码更容易编写、调试和维护
解耦——使耦合更松散
- 可以改变一个而不影响另一个
- 帮助编写单元测试
线程池
在组或池中安排线程
完成一项特定的任务
现在我们将使用一个线程数组
下一个模块将展示如何使用threadpoolexecutor
当初的需求
客户池中的每个线程代表一组用餐者
- 顾客随机到达,等待服务员入座
- 只有在他们到达得不太晚的情况下才会提供服务
- 如果他们在打烊前到达,他们就可以吃饭
任何服务员都可以提出任何要求
当初的需求
客户请求服务员:
- ——点菜
- 要求带饭
- 携带支票
客户付款后离开
在关门时间:
- 未就座的顾客被拒之门外
- 服务员可以回家了
- 酒吧关门
示例:
代码实现
自旋锁的代码片段
示例:
改善了服务员不会一直旋转,顾客等待处理请求。
用wait()/ notify()/ notifyAll() - 小节
wait()/ notify()/ notifyAll()
提供基本的信号
需要信号调用的线程等待
- 休眠,直到另一个线程调用notify()/notifyAll()
notify()唤醒一个等待对象的线程
notifyAll()唤醒所有等待对象的线程
等待集
等待需要一个条件变量,即等待集
- 这将排队等待线程
- 对象与等待集相关联
在调用wait()/notify()/notifyAll()之前使用synchronized(对象)
- 否则抛出IllegalMonitorStateException
等待设置杂集
不应该使用wait on Thread或任何扩展它的东西
Wait有超时版本[ms,ms & ns]
像加入
- 超时的O调用非超时版本
- 但不是在不等待的时间单位版本
- 来电显示是否超时或中断
等待抛出InterruptedException
需要注意的危险
lllegalMonitorStateException is thrown if:
- 忘记synchronize
- 同步错误的对象
等待和监控
当线程添加到等待集时
- 释放其监控
- 其他线程可以调用wait或notify
当线程从等待中唤醒时
- 唤醒的线程重新获得监视器
等待和监控
通知线程应该尽快释放monitor
- 否则可能会导致饥饿
notifyAll()导致所有等待的线程重新获得monitor
- 退出wait()-单线程
- 别等太久
由于释放监视器,请注意竞态条件
虚假的唤醒
由于硬件优化
导致线程在未调用notify()的情况下从wait()中唤醒
- 这可能会导致细微的bug
无需等待线程的通知
不存储通知
- 信号丢失
- 可能导致线程永远等待
修正了在while循环中封装wait()的问题
失去了通知的问题
与通知同时中断
- 不知道是否被通知[但可以查看队列]
当中断意味着不再处理任何工作时,没有问题
如果需要处理工作
- 记得在做出色的工作时被打断过
notify()和notifyAll ()
觉醒机制可能不公平
- notify,同一线程可能会唤醒导致饥饿
如果在同一对象上等待不同的条件
- 错误的线程可能唤醒和信号丢失
- 认定使用notifyAll ()
示例:
wait/notify的使用
BlockingQueue - 小节
BlockingQueue介绍
BlockingQueue是一个接口
- LinkedBlockingQueue-linked list版本,它没有被填满
- ArrayBlockingQueue-array列表版本的固定大小
固定大小可以防止队列增长过大
- 当生产者留下的工作超过消费者的消费能力
示例:
我们将升级模拟,使用LinkedBlockingQueue
总结 - 小节
生产者/消费者模式
生产者发送消息给消费者进行消费
分裂成生产者/消费者:
- 分离关系-更高的凝聚力
- 通过队列松散耦合进行交互
四个实现
不断轮询,自旋锁消耗CPU
在轮询之间睡觉、等待太频繁或响应性降低
wait()/ notify()
BlockingQueue
wait()/ notify()/ notifyAll()
wait()/ notify()/ notifyAll()是对象上的方法
- 必须同步的对象,他们被调用
notify()向等待对象的线程发出信号
notifyAll()向所有等待对象的线程发出信号
While循环条件的使用
Handling伪唤醒和通知信号竞争条件
- 同步时发出信号的线程更新状态
处理中断和超时
- 中断和信号同时到达的危险
wait()/notify()将暴露给我们其他问题
忘记同步对象
在错误的对象上同步
- llegalmonitorstate异常-仅在运行时发现
失踪的通知
当线程在不同条件下等待时,使用notify()
- 导致“死锁”;没有进一步的信号唤醒线程
BlockingQueue
让生活变得简单
应该尽可能使用更高级别的实现
- 级别较低的wait()/notify()可能很难正确执行