Java - JVM - 线程时间片的其他操作
-
概述
- Java 线程偏向于 时间片 的操作
-
背景
-
之前了解 围绕监视器锁 的一些线程操作
- synchronized
- wait(), notify(), notifyAll()
-
但是还有别的问题, 没有覆盖到
-
问题
- 我想让我的线程 在不释放锁 的情况下, 停止一段时间
- 我想让我的线程, 放弃现在的 时间片
- 我想让我的线程, 排在别的线程之后
-
这些问题, 光靠 监视器锁, 好像解决不了
- 没关系, 我们还有别的工具
-
1. 睡眠
-
概述
- 线程暂停
-
场景: 轮询
- 问题
-
线程轮询时, 如果一直高频率询问, 会有弊端
- 高频询问消耗 cpu 资源
- 高频询问, 很多次询问, 都是无效的
-
解决
- 一次轮询失败后, 休息一段时间, 再尝试下一次轮询
-
- 问题
-
sleep()
-
概述
- 让当前线程, 停止一段时间, 然后继续
-
解释
-
当前线程
- 只能给 当前线程 使用
- 源码注释
- static 方法
- 只能给 当前线程 使用
-
停止
- 具体机制
- 将当前线程转换到 wait 状态
- 线程状态?
- 不执行任何代码
- 消耗最少的资源
- 等待 调度器 唤醒
- 线程状态?
- 将当前线程转换到 wait 状态
- 具体机制
-
一段时间
- 单位
- ms
- 定义
- 时间是由 调用者 设定的
- 单位
-
继续
- 继续上次的执行
- 从 sleep 下一句开始
- 继续上次的执行
-
-
-
问题
- sleep 的时间, 可能会不准确
-
状态
- sleep 被唤醒后, 是 可执行状态
- 可执行 到 执行中, 会有一个 时间
-
线程调度
- sleep 从 wait 到 被唤醒, 到 分配到时间片执行, 中间需要若干个 线程调度 的步骤
- 不同的 jvm 实现, 可能会有所差异
-
误差
- 误差通常在 10ms 左右吧
-
- sleep 的时间, 可能会不准确
-
注意
-
sleep 不会对锁有影响
- 可以在 同步/非同步 代码里执行
- sleep 不会改变锁的 持有情况
-
sleep 如果被打断, 会抛出异常
- InterruptedException
- 这个后续再说
-
2. 让步
-
概述
- 让步
-
场景: ...
- 尴尬了
- 老实说, 我也不知道这有什么场景
- 源码里提到, 这个方法在 java.util.concurrent.locks 的代码测试中有过使用
- 作用
- 收回当前线程的 时间片, 让线程重新回到 runable 阶段
- 重新开展 线程调度
- 尴尬了
-
yield()
-
概述
- 让当前线程, 让出 cpu 时间片
-
解释
-
当前线程
- 同 sleep
-
让出 cpu 世间片
- 线程的执行, 需要 cpu时间片
- 让出 cpu时间片, 则 线程不再执行
- 通常线程会回到 runable 阶段, 重新参与调度
-
-
-
注意
- 可能会被部分 jvm 忽略
- yield 不会对锁 有影响
- 同 sleep
3. 合成
-
概述
- 合成
-
场景: 先后执行
-
先后执行
- 线程T1 需要等待 线程T2 的执行结果
- 线程T1 持有 线程T2 的引用
-
疑问
- 为啥不用 监视器锁
- 有些代码实现, 没有用 synchronized, 我想等这块的东西, 但又不想改代码
- 为啥不用 监视器锁
-
-
join()
-
概述
- 等待其他线程执行结束, 然后继续
-
解释
-
等待
- 保持 wait 状态
- 持续执行 wait 方法
- 机制
- T1 执行 T2 的 join 方法
- 带时间参数的 join, 竟然是 同步方法
- T1 获得 T2 的 锁
- 没错, 是 线程T2 对应 Thread 对象的锁
- 这个 通常 不会影响 T2 正在执行的任务
- 但是如果真的被阻塞了, 确实需要等在那里
- T1 开始循环, 判断 T2 是否存活
- 如果 T2 存活, 则一直 wait()
- wait() 就意味着锁...
- 如果 T2 存活, 则一直 wait()
- T1 执行 T2 的 join 方法
- 保持 wait 状态
-
其他线程
- join 需要持有其他线程的引用
-
继续
- join 回来后, 从 wait 后面的代码开始, 继续执行
-
-
-
问题: 抱歉, 这俩问题, 我现在无法解答
-
T1 在 wait 阶段, T2 还活着, T1 是怎么被唤醒的
-
同步方法是不是意味着, 只能有一个 T2 的 join, 只能被一个线程调用
- 如果多个线程调用 wait, 会是怎样一种请情况
-
T2 线程如果出现了异常, T1 会是怎么样一种反应?
-
-
注意
- join 途中, 如果被打断, T1 会抛出异常
- InterruptedException
- 怎么又是你
- InterruptedException
- join 途中, 如果被打断, T1 会抛出异常
4. 后续
-
线程状态
- 说了这么线程相关的方法, 终于该说这个线程状态了
- 之前想尝试先讲状态, 但是写了点发现越写越难写
- 说了这么线程相关的方法, 终于该说这个线程状态了
-
Java 内存模型
- Java 内存模型, 其实很复杂
-
多线程
- 终于到这一步了...
ps
- ref
- Java 语言规范(SE 8th)
- Java Thread sleep
- 简单清晰
- Java 核心技术(10th editon) 卷1
- Java多线程中join方法的理解
- 讲得挺好
- 作者后来还成了 携程某部门的 CTO, 还创立了 优知学院, 挺厉害的
尽量尝试解释清楚; 自己校对能力有限, 如果有错误欢迎指出