Java - JVM - 线程时间片的其他操作

  1. 概述

    1. Java 线程偏向于 时间片 的操作
  2. 背景

    1. 之前了解 围绕监视器锁 的一些线程操作

      1. synchronized
      2. wait(), notify(), notifyAll()
    2. 但是还有别的问题, 没有覆盖到

    3. 问题

      1. 我想让我的线程 在不释放锁 的情况下, 停止一段时间
      2. 我想让我的线程, 放弃现在的 时间片
      3. 我想让我的线程, 排在别的线程之后
    4. 这些问题, 光靠 监视器锁, 好像解决不了

      1. 没关系, 我们还有别的工具

1. 睡眠

  1. 概述

    1. 线程暂停
  2. 场景: 轮询

    1. 问题
      1. 线程轮询时, 如果一直高频率询问, 会有弊端

        1. 高频询问消耗 cpu 资源
        2. 高频询问, 很多次询问, 都是无效的
      2. 解决

        1. 一次轮询失败后, 休息一段时间, 再尝试下一次轮询
  3. sleep()

    1. 概述

      1. 让当前线程, 停止一段时间, 然后继续
    2. 解释

      1. 当前线程

        1. 只能给 当前线程 使用
          1. 源码注释
        2. static 方法
      2. 停止

        1. 具体机制
          1. 将当前线程转换到 wait 状态
            1. 线程状态?
              1. 不执行任何代码
              2. 消耗最少的资源
              3. 等待 调度器 唤醒
      3. 一段时间

        1. 单位
          1. ms
        2. 定义
          1. 时间是由 调用者 设定的
      4. 继续

        1. 继续上次的执行
          1. 从 sleep 下一句开始
  4. 问题

    1. sleep 的时间, 可能会不准确
      1. 状态

        1. sleep 被唤醒后, 是 可执行状态
        2. 可执行 到 执行中, 会有一个 时间
      2. 线程调度

        1. sleep 从 wait 到 被唤醒, 到 分配到时间片执行, 中间需要若干个 线程调度 的步骤
        2. 不同的 jvm 实现, 可能会有所差异
      3. 误差

        1. 误差通常在 10ms 左右吧
  5. 注意

    1. sleep 不会对锁有影响

      1. 可以在 同步/非同步 代码里执行
      2. sleep 不会改变锁的 持有情况
    2. sleep 如果被打断, 会抛出异常

      1. InterruptedException
      2. 这个后续再说

2. 让步

  1. 概述

    1. 让步
  2. 场景: ...

    1. 尴尬了
      1. 老实说, 我也不知道这有什么场景
      2. 源码里提到, 这个方法在 java.util.concurrent.locks 的代码测试中有过使用
    2. 作用
      1. 收回当前线程的 时间片, 让线程重新回到 runable 阶段
      2. 重新开展 线程调度
  3. yield()

    1. 概述

      1. 让当前线程, 让出 cpu 时间片
    2. 解释

      1. 当前线程

        1. 同 sleep
      2. 让出 cpu 世间片

        1. 线程的执行, 需要 cpu时间片
        2. 让出 cpu时间片, 则 线程不再执行
        3. 通常线程会回到 runable 阶段, 重新参与调度
  4. 注意

    1. 可能会被部分 jvm 忽略
    2. yield 不会对锁 有影响
      1. 同 sleep

3. 合成

  1. 概述

    1. 合成
  2. 场景: 先后执行

    1. 先后执行

      1. 线程T1 需要等待 线程T2 的执行结果
      2. 线程T1 持有 线程T2 的引用
    2. 疑问

      1. 为啥不用 监视器锁
        1. 有些代码实现, 没有用 synchronized, 我想等这块的东西, 但又不想改代码
  3. join()

    1. 概述

      1. 等待其他线程执行结束, 然后继续
    2. 解释

      1. 等待

        1. 保持 wait 状态
          1. 持续执行 wait 方法
        2. 机制
          1. T1 执行 T2 的 join 方法
            1. 带时间参数的 join, 竟然是 同步方法
          2. T1 获得 T2 的 锁
            1. 没错, 是 线程T2 对应 Thread 对象的锁
            2. 这个 通常 不会影响 T2 正在执行的任务
            3. 但是如果真的被阻塞了, 确实需要等在那里
          3. T1 开始循环, 判断 T2 是否存活
            1. 如果 T2 存活, 则一直 wait()
              1. wait() 就意味着锁...
      2. 其他线程

        1. join 需要持有其他线程的引用
      3. 继续

        1. join 回来后, 从 wait 后面的代码开始, 继续执行
  4. 问题: 抱歉, 这俩问题, 我现在无法解答

    1. T1 在 wait 阶段, T2 还活着, T1 是怎么被唤醒的

    2. 同步方法是不是意味着, 只能有一个 T2 的 join, 只能被一个线程调用

      1. 如果多个线程调用 wait, 会是怎样一种请情况
    3. T2 线程如果出现了异常, T1 会是怎么样一种反应?

  5. 注意

    1. join 途中, 如果被打断, T1 会抛出异常
      1. InterruptedException
        1. 怎么又是你

4. 后续

  1. 线程状态

    1. 说了这么线程相关的方法, 终于该说这个线程状态了
      1. 之前想尝试先讲状态, 但是写了点发现越写越难写
  2. Java 内存模型

    1. Java 内存模型, 其实很复杂
  3. 多线程

    1. 终于到这一步了...

ps

  1. ref
    1. Java 语言规范(SE 8th)
    2. Java Thread sleep
      1. 简单清晰
    3. Java 核心技术(10th editon) 卷1
    4. Java多线程中join方法的理解
      1. 讲得挺好
      2. 作者后来还成了 携程某部门的 CTO, 还创立了 优知学院, 挺厉害的
        1. 分布式架构详解
posted @ 2020-05-21 13:53  轩辕拾銉  阅读(794)  评论(0编辑  收藏  举报