ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

25张图吃透JVM偏向锁:从Mark Word到批量撤销的完整指南

25张图吃透JVM偏向锁:从Mark Word到批量撤销的完整指南 偏 向 锁 这 个 概 念 一 直 是 JVM 面 试 和 线 上 性 能 问 题 里 的“ 顶 流 话 题 ”。 我 自 己 就 有 一 次 印 象 很 深 的 经 历 压 测 时 线 程 数 不 多 并 发 压 力 也 没 到 峰 值 但 吞 吐 量 就 是 上 不 去 后 来 打 开 JFR 才 发 现 高 频 的 偏 向 锁 撤 销 引 发 了 一 连 串 的 safepoint 暂 停 整 个 应 用 的 顿 挫 感 全 是 它 造 成 的 。 那 个 时 候 我 才 真 正 理 解 为 什 么 大 家 说 这 是 一 个“ 又 爱 又 恨 ”的 机 制 用 好 了 它 能 砍 掉 同 步 块 的 大 部 分 开 销 碰 上 竞 争 剧 烈 的 场 景 它 反 而 会 拖 着 整 个 JVM 停 下 来 做 “ 清 算 ”。这 篇 文 章 我 会 把 偏 向 锁 从 设 计 动 机 、 对 象 头 布 局 、 获 取 与 撤 销 流 程 、 批 量 重 偏 向 与 批 量 撤 销 一 直 讲 到 JDK 15 为 什 么 默 认 关 闭 它 。 标 题 说 是 “ 25 张 图 吃 透 ” 文 章 里 我 会 用 表 格 和 示 意 结 构 代 替 图 的 信 息 量 你 看 完 之 后 不 仅 能 回 答 面 试 题 更 能 在 实 际 项 目 里 判 断 什 么 时 候 该 留 着 它 、 什 么 时 候 干 脆 关 掉 。1. 为什么会有偏向锁JVM 向“没有竞争”的现实低头1.1 synchronized 从重量级到分级锁的演进很 多 人 第 一 次 学 synchronized 的 时 候 背 的 都 是 “ 同 步 块 会 阻 塞 线 程 ” 这 套 解 释 。 这 其 实 是 早 期 实 现 的 局 限 性 。 JDK 1.5 之 前 synchronized 直 接 对 应 操 作 系 统 级 的 monitor 机 制 也 就 是 重 量 级 锁 线 程 抢 不 到 锁 就 挂 起 等 到 锁 释 放 再 唤 醒 。 这 里 面 涉 及 内 核 态 切 换 代 价 极 高 即 使 同 一 个 线 程 反 复 进 入 同 一 个 同 步 块 也 要 走 完 整 套 流 程 。所 以 JDK 6 对 synchronized 做 了 一 次 大 改 造 引 入 了 偏 向 锁 和 轻 量 级 锁 把 原 来 “ 要 么 无 锁 、 要 么 重 量 级 ” 的 二 元 模 式 变 成 了 无 锁 → 偏 向 锁 → 轻 量 级 锁 → 重 量 级 锁 的 分 级 模 型 。 级 别 越 高 竞 争 越 激 烈 开 销 也 越 大 。 这 个 设 计 背 后 的 逻 辑 很 直 接 JVM 希 望 用 最 便 宜 的 方 式 处 理 大 多 数 场 景 只 有 在 确 实 需 要 强 排 他 的 时 候 才 动 用 昂 贵 的 内 核 机 制 。 偏 向 锁 就 是 这 套 分 级 体 系 里 最 “ 吝 啬 ” 的 一 档 。1.2 偏向锁想解决的问题你 想 一 个 很 典 型 的 场 景 线 程 A 每 次 循 环 都 要 调 用 某 个 同 步 方 法 比 如 一 个 被 synchronized 修 饰 的 累 加 器 而 整 个 应 用 里 只 有 线 程 A 会 碰 它 。 从 竞 争 的 角 度 看 这 里 根 本 没 有 “ 竞 争 ” 只 是 同 一 个 线 程 在 反 复 进 门 。如 果 用 轻 量 级 锁 来 处 理 每 次 进 门 都 要 做 一 次 CAS 操 作 把 对 象 头 里 的 Mark Word 复 制 到 栈 帧 的 Lock Record 里 虽 然 比 重 量 级 锁 快 得 多 但 依 然 是 一 次 实 打 实 的 原 子 操 作 。 在 极 高 频 的 场 景 下 这 个 CAS 也 会 积 累 成 可 观 的 CPU 消 耗 。偏 向 锁 的 解 决 方 案 很 “ 偷 懒 ” 既 然 只 有 线 程 A 在 用 那 就 直 接 在 对 象 头 上 写 下 “ 这 个 锁 属 于 线 程 A ” 的 标 记 。 之 后 线 程 A 再 进 来 只 要 看 到 标 记 是 自 己 连 CAS 都 省 了 直 接 进 入 临 界 区 。 无 竞 争 场 景 下 偏 向 锁 的 开 销 接 近 于 零 。1.3 用一句话说清偏向锁的核心理念我 给 别 人 解 释 偏 向 锁 的 时 候 常 用 一 个 图 书 馆 的 比 喻 。 图 书 馆 的 研 究 室 平 时 只 有 一 个 老 顾 客 使 用 门 卫 认 识 他 之 后 每 次 他 来 直 接 放 行 不 用 掏 证 件 登 记 。 这 就 是 偏 向 锁 的 “ 刷 脸 式 ” 优 化 。但 问 题 也 在 这 里 一 旦 某 天 来 了 第 二 个 人 要 进 这 间 研 究 室 门 卫 就 必 须 先 把 老 顾 客 的 登 记 信 息 撤 掉 重 新 处 理 两 个 人 的 争 夺 。 这 个 “ 撤 销 登 记 ” 的 过 程 反 而 比 直 接 登 记 还 要 贵 。 后 面 第 5 章 会 详 细 讲 批 量 撤 销 的 机 制 那 正 是 JVM 面 对 “ 第 二 个 人 频 繁 出 现 ” 时 的 补 救 措 施 。2. 先看懂 Mark Word偏向锁在对象头里到底存了什么2.1 对象头与 Mark Word 的多功能复用HotSpot 里 每 个 对 象 的 内 存 布 局 大 致 是 Mark Word 、 Klass Pointer 、 实 例 数 据 、 对 齐 填 充 。 Mark Word 是 一 个 非 常 特 别 的 字 段 它 不 是 固 定 存 某 种 信 息 的 而 是 根 据 对 象 的 锁 状 态 灵 活 复 用 那 64 个 bit 。对 象 是 无 锁 状 态 时 Mark Word 里 存 的 是 identity hash code 和 分 代 年 龄 处 于 偏 向 锁 状 态 时 同 样 的 64 个 bit 就 要 腾 出 大 部 分 空 间 存 线 程 ID 和 epoch 处 于 轻 量 级 锁 状 态 时 里 面 存 的 是 指 向 栈 中 Lock Record 的 指 针 处 于 重 量 级 锁 状 态 时 里 面 存 的 是 指 向 monitor 对 象 的 指 针 。这 就 解 释 了 后 面 很 多 看 似 “ 奇 怪 ” 的 限 制 比 如 一 个 对 象 已 经 算 过 identity hash code 它 就 没 办 法 再 进 入 偏 向 锁 状 态 因 为 那 个 hash 值 占 用 的 正 是 偏 向 锁 想 要 的 位 置 。 这 些 信 息 互 斥 不 能 共 存 。2.2 64 位 JVM 下偏向锁态与无锁态的位布局很 多 资 料 里 会 画 一 张 精 细 的 位 布 局 图 我 用 表 格 还 原 一 下 核 心 信 息 。 注 意 具 体 的 bit 数 因 JVM 版 本 和 平 台 略 有 差 异 经 典 资 料 里 通 常 是 这 么 描 述 的 Mark Word 状态线程 IDepoch分代年龄biased_locklock 位说明无锁不 存 储 (存 hash 等)—4 bit001可 以 存 放 identity hash code偏向锁54 bit 左 右2 bit4 bit101存 储 持 有 者 线 程 与 批 次轻量级锁指 向 Lock Record———00存 放 栈 帧 中 的 锁 记 录 地 址重量级锁指 向 monitor———10存 放 monitor 对 象 地 址GC 标 记空———11对 象 处 于 GC 回 收 标 记 阶 段看 到 那 个 “ lock01 且 biased_lock1 ” 的 组 合 了 吗 偏 向 锁 和 无 锁 的 lock 位 都 是 01 唯 一 的 区 别 就 是 biased_lock 这 个 标 志 位 。 因 此 判 断 一 个 对 象 是 否 可 偏 向 、 是 否 已 偏 向 核 心 就 是 看 这 两 个 比 特 的 组 合 以 及 线 程 ID 字 段 是 否 为 空 。打 个 比 方 Mark Word 就 像 一 个 宿 舍 的 门 牌 板 没 人 住 的 时 候 挂 着 “ 空 房 ” 有 人 长 期 独 住 就 写 上 他 的 名 字 要 是 两 个 人 抢 起 来 了 宿 管 员 干 脆 把 门 牌 换 成 一 个 指 向 “ 调 解 室 ” 的 指 示 牌 。2.3 epoch 字段的直觉理解epoch 这 个 词 看 上 去 很 高 级 其 实 就 是 “ 批 次 号 ” 。 每 个 类 都 维 护 一 个 全 局 的 bias epoch 当 类 里 的 对 象 被 偏 向 时 Mark Word 里 会 记 录 当 时 的 类 epoch 值 。当 JVM 发 现 这 个 类 的 偏 向 撤 销 达 到 一 定 次 数 决 定 做 批 量 重 偏 向 时 就 会 把 类 的 全 局 epoch 加 一 。 已 经 偏 向 的 对 象 里 存 的 还 是 旧 epoch 相 当 于 “ 旧 批 次 的 车 票 ” 新 一 次 锁 获 取 时 只 要 比 对 epoch 不 匹 配 就 视 为 偏 向 过 期 可 以 直 接 重 新 偏 向 给 新 线 程 。 这 个 机 制 是 后 面 第 5 章 的 基 础 先 在 这 里 留 个 印 象 。3. 偏向锁的一生获取、重复进入、撤销、升级3.1 启动延迟为什么默认要等 4 秒很 多 人 不 知 道 JVM 启 动 后 的 前 几 秒 里 偏 向 锁 是 不 工 作 的 。 HotSpot 默 认 的-XX:BiasedLockingStartupDelay4000 也 就 是 启 动 后 4 秒 之 内 同 步 块 直 接 走 无 锁 或 轻 量 级 锁 路 径 不 尝 试 偏 向 。为 什 么 要 这 样 设 计 应 用 刚 启 动 的 时 候 会 创 建 大 量 线 程 业 务 线 程 和 各 种 后 台 线 程 都 在 抢 占 资 源 偏 向 关 系 极 不 稳 定 。 如 果 马 上 让 对 象 偏 向 到 某 个 线 程 很 快 就 会 因 为 线 程 切 换 而 被 撤 销 反 而 浪 费 性 能 。 等 几 秒 让 线 程 分 布 稳 定 下 来 再 开 启 偏 向 才 能 更 大 概 率 地 命 中 “ 单 线 程 反 复 使 用 ” 的 场 景 。压 测 的 时 候 我 们 经 常 会 看 到 有 人 把 这 个 延 迟 调 成 0 用 于 在 短 时 间 压 力 测 试 里 尽 快 触 发 偏 向 锁 的 各 种 行 为 本 地 复 现 问 题 很 管 用 但 生 产 环 境 我 不 建 议 随 便 动 它 。3.2 获取偏向锁的完整路径当 对 象 处 于 可 偏 向 状 态 时 线 程 获 取 锁 的 路 径 是 这 样 的 首 先 检 查 对 象 头 的 biased_lock 位 是 否 为 1 。 如 果 为 0 说 明 对 象 已 经 不 可 偏 向 直 接 走 轻 量 级 锁 逻 辑 。如 果 可 偏 向 再 看 线 程 ID 字 段 是 否 为 空 。 为 空 说 明 处 于 “ 匿 名 偏 向 ” 状 态 任 何 线 程 都 可 以 尝 试 用 CAS 把 自 己 的 线 程 ID 写 进 去 。 写 成 功 这 个 对 象 就 偏 向 到 当 前 线 程 了 。如 果 线 程 ID 已 经 是 当 前 线 程 说 明 偏 向 已 经 属 于 自 己 直 接 进 入 临 界 区 这 是 整 个 偏 向 锁 体 系 里 最 快 的 路 径 。如 果 线 程 ID 是 其 他 线 程 说 明 出 现 了 竞 争 马 上 进 入 撤 销 流 程 。第 二 步 里 的 CAS 值 得 多 说 两 句 。 匿 名 偏 向 状 态 下 是 允 许 竞 争 的 多 个 线 程 同 时 试 图 偏 向 同 一 个 对 象 也 是 可 能 的 所 以 JVM 需 要 用 CAS 保 证 只 有 一 个 线 程 能 写 入 成 功 。 只 是 这 个 CAS 通 常 只 发 生 在 对 象 第 一 次 被 线 程 使 用 的 时 候 后 面 就 再 也 不 用 了 。3.3 偏向撤销的两种结局偏 向 锁 撤 销 是 本 文 最 关 键 的 部 分 也 是 它 “ 招 恨 ” 的 根 源 。 撤 销 并 不 是 简 单 地 把 标 记 抹 掉 而 是 要 等 待 一 个 全 局 safepoint 也 就 是 让 所 有 Java 线 程 暂 停 下 来 然 后 检 查 原 持 有 线 程 的 状 态 。如 果 原 持 有 线 程 还 在 执 行 同 步 块 代 码 说 明 竞 争 是 真 实 的 直 接 把 对 象 头 升 级 为 轻 量 级 锁 让 两 个 线 程 走 正 常 的 CAS 抢 锁 路 径 。如 果 原 持 有 线 程 已 经 退 出 了 同 步 块 说 明 之 前 的 偏 向 已 经 “ 过 期 ” 就 把 对 象 头 重 置 为 无 锁 或 者 可 重 新 偏 向 的 状 态 。这 里 有 一 个 非 常 重 要 的 认 知 偏 向 锁 的 撤 销 是 一 次 全 局 性 的 暂 停 操 作 。 单 个 对 象 的 撤 销 可 能 只 是 微 秒 级 的 抖 动 但 如 果 同 一 个 类 的 很 多 对 象 同 时 需 要 撤 销 safepoint 的 耗 时 就 会 急 剧 上 升 表 现 在 业 务 上 就 是 周 期 性 的 延 迟 毛 刺 。 我 开 头 提 到 的 压 测 问 题 就 是 这 个 原 因 引 起 的 。3.4 从轻量级到重量级的升级链路偏 向 锁 撤 销 后 并 不 是 直 接 到 重 量 级 锁 。 通 常 的 路 径 是 先 升 级 为 轻 量 级 锁 线 程 把 对 象 头 的 Mark Word 复 制 到 自 己 栈 帧 的 Lock Record 中 然 后 用 CAS 把 对 象 头 里 的 Mark Word 替 换 成 指 向 Lock Record 的 指 针 。 一 旦 CAS 失 败 说 明 另 有 线 程 也 在 抢 于 是 继 续 膨 胀 为 重 量 级 锁 进 入 monitor 后 续 竞 争 线 程 就 要 被 挂 起 等 待 了 。锁 状 态 的 主 流 方 向 是 偏 向 → 轻 量 → 重 量 。 网 上 经 常 说 “ 锁 只 能 升 级 不 能 降 级 ” 这 个 说 法 在 很 长 一 段 时 间 内 符 合 大 部 分 观 测 结 果 但 新 一 些 的 HotSpot 版 本 在 safepoint 里 也 有 锁 降 级 的 实 现 只 是 对 业 务 层 面 而 言 很 难 观 察 到 。 面 试 的 时 候 你 可 以 说 “ 主 路 径 是 升 级 ” 但 不 要 把 “ 绝 对 不 降 级 ” 说 死 。4. hashCode 是偏向锁的头号克星一次调用就前功尽弃4.1 identityHashCode 存在 Mark Word 里Java 每 个 对 象 都 有 一 个 identity hash code 不 重 写 hashCode 的 时 候 Object.hashCode 返 回 的 就 是 它 。 这 个 值 一 般 是 懒 计 算 的 第 一 次 调 用 时 生 成 之 后 缓 存 在 Mark Word 的 无 锁 区 域 里 。问 题 就 在 这 里 偏 向 锁 需 要 用 Mark Word 存 线 程 ID 和 epoch 而 identity hash code 也 需 要 存 Mark Word 。 这 两 个 东 西 都 想 占 用 同 一 块 空 间 所 以 它 们 是 互 斥 的 。 我 前 面 的 表 格 里 那 一 行 “ 无 锁 状 态 可 以 存 放 identity hash code ” 的 含 义 正 是 如 此 。4.2 调用 hashCode 后到底会发生什么如 果 一 个 对 象 已 经 处 于 偏 向 锁 状 态 此 时 有 代 码 调 用 了 System.identityHashCode 或 未 重 写 的 Object.hashCode JVM 就 必 须 把 偏 向 撤 销 让 Mark Word 腾 出 空 间 来 存 那 个 hash 值 。 撤 销 之 后 这 个 对 象 就 不 能 再 偏 向 了 因 为 它 的 Mark Word 永 远 需 要 预 留 位 置 存 hash 。反 过 来 也 成 立 如 果 某 个 对 象 在 获 取 锁 之 前 就 已 经 算 过 identity hash code 它 的 Mark Word 里 就 有 存 储 需 求 这 个 对 象 从 根 本 上 就 失 去 了 进 入 偏 向 锁 状 态 的 资 格 。 每 次 进 同 步 块 都 只 能 走 轻 量 级 锁 或 更 高 级 别 的 路 径 。很 多 人 会 混 淆 一 点 重 写 了 hashCode 方 法 的 对 象 不 受 这 个 限 制 。 因 为 重 写 之 后 返 回 的 是 你 自 己 算 的 Java 层 值 存 在 对 象 的 实 例 字 段 里 或 者 每 次 临 时 计 算 根 本 不 会 写 入 Mark Word 。 会 触 发 偏 向 锁 撤 销 的 只 有 identity hash code 这 个 “ 原 生 ” 值 。4.3 生产环境里哪些场景会踩中举 几 个 实 际 会 踩 中 的 场 景 把 对 象 放 进 IdentityHashMap 因 为 它 的 键 比 较 依 赖 identity hash code 很 容 易 触 发 偏 向 锁 对 象 的 撤 销 。使 用 调 试 器 观 察 对 象 某 些 工 具 会 间 接 调 用 identityHashCode 。一 些 序 列 化 框 架 或 代 理 生 成 过 程 中 需 要 用 对 象 的 identity 信 息 。这 些 场 景 的 共 同 点 是 你 根 本 无 法 从 业 务 代 码 里 直 接 看 出 来 偏 向 锁 什 么 时 候 丢 失 了 。 这 也 是 为 什 么 本 地 复 现 性 能 问 题 时 开 着 调 试 器 测 出 来 的 锁 行 为 和 生 产 环 境 往 往 不 一 致 。 我 的 建 议 是 做 锁 性 能 对 照 实 验 的 时 候 尽 量 不 挂 调 试 器 否 则 结 论 容 易 被 带 偏 。5. 批量重偏向与批量撤销JVM 的“亡羊补牢”机制5.1 为什么需要批处理机制如 果 每 个 对 象 都 单 独 撤 销 那 偏 向 锁 在 线 程 切 换 频 繁 的 场 景 里 就 完 全 是 负 优 化 了 。 幸 好 HotSpot 提 供 了 两 个 启 发 式 批 处 理 机 制 基 于 每 个 类 的 撤 销 计 数 器 做 判 断 。每 个 类 都 有 一 个 全 局 的 撤 销 计 数 器 。 当 某 个 类 的 对 象 发 生 偏 向 锁 撤 销 时 计 数 器 就 加 一 。 加 到 一 定 程 度 JVM 会 认 为 这 个 类 的 偏 向 行 为 已 经 出 现 系 统 性 问 题 需 要 在 类 层 面 做 调 整 而 不 是 继 续 跟 单 个 对 象 较 劲 。5.2 批量重偏向当对象整体换主人触 发 条 件 是 撤 销 次 数 达 到-XX:BiasedLockingBulkRebiasThreshold的 阈 值 默 认 是 20 。 此 时 JVM 会 把 类 的 全 局 epoch 加 一 之 前 所 有 已 偏 向 对 象 里 存 的 旧 epoch 都 会 在 下 一 次 锁 获 取 时 被 判 定 为 “ 过 期 ” 于是 新 线 程 可 以 直 接 用 CAS 重 新 偏 向 而 不 必 走 完 整 的 撤 销 流 程 。 这 个 机 制 特 别 适 合 “ 对 象 整 批 从 线 程 A 迁 移 到 线 程 B ” 的 场 景 比 如 线 程 池 中 任 务 被 重 新 调 度 。必 须 强 调 一 点 批 量 重 偏 向 不 是 “ 零 成 本 ” 更 新 类 级 别 的 epoch 本 身 也 需 要 一 次 短 暂 的 全 局 协 调 。 但 相 比 于 对 每 个 对 象 逐 个 撤 销 、 逐 个 判 断 原 持 有 线 程 状 态 这 个 成 本 已 经 低 得 多 了 。5.3 批量撤销彻底宣告这个类不适合偏向如 果 同 一 个 类 继 续 恶 化 撤 销 次 数 达 到-XX:BiasedLockingBulkRevokeThreshold 默 认 是 40 JVM 就 会 做 出 更 激 进 的 决 策 把 整 个 类 标 记 为 不 可 偏 向 。 之 后 这 个 类 的 新 对 象 在 创 建 时 就 会 直 接 放 弃 偏 向 锁 的 可 能 性 已 经 偏 向 的 对 象 也 会 在 后 续 访 问 中 被 处 理 掉 。为 什 么 是 40 这 个 数 字 表 明 的 是 一 种 态 度 如 果 一 个 类 有 那 么 多 对 象 在 频 繁 地 发 生 偏 向 撤 销 那 说 明 竞 争 已 经 成 为 常 态 偏 向 锁 的 “ 单 线 程 假 设 ” 在 这 个 类 上 不 成 立 。 继 续 维 持 偏 向 只 会 徒 增 撤 销 开 销 不 如 干 脆 关 掉 。5.4 衰减计时器防止偶发事件误伤好类还 有 一 个 容 易 被 忽 略 的 参 数-XX:BiasedLockingDecayTime 默 认 值 25000 毫 秒 。 它 的 作 用 是 当 撤 销 事 件 发 生 后 如 果 经 过 25 秒 没 有 新 的 撤 销 计 数 器 就 会 衰 减 一 半 或 重 置 。这 个 设 计 的 意 思 是 一 个 类 偶 尔 被 多 线 程 碰 一 下 不 应 该 被 永 久 拉 黑 。 比 如 应 用 启 动 阶 段 出 现 了 一 波 临 时 性 竞 争 之 后 整 个 运 行 期 都 很 平 静 那 么 衰 减 机 制 能 让 这 个 类 保 留 “ 恢 复 可 偏 向 ” 的 机 会 。 这 也 是 JVM 在 “ 爱 ” 与 “ 恨 ” 之 间 做 的 补 偿 平 衡 。5.5 压测中的真实观察我 在 本 地 做 过 一 次 对 照 实 验 让 8 个 线 程 轮 流 进 入 同 一 个 同 步 块 对 象 是 同 一 个 实 例 。 前 20 次 撤 销 发 生 得 很 快 之 后 观 察 到 safepoint 的 间 隔 有 明 显 变 化 而 当 撤 销 次 数 到 达 40 左 右 时 这 个 类 的 对 象 就 完 全 不 再 走 偏 向 路 径 了 。 对 业 务 的 直 观 感 受 就 是 前 几 秒 钟 会 出 现 几 个 明 显 的 停 顿 之 后 反 而 稳 定 下 来 因 为 锁 已 经 定 位 到 了 更 合 适 的 机 制 。如 果 你 在 线 上 遇 到 类 似 的 “ 周 期 性 毛 刺 又 看 不 到 GC 问 题 ” 可 以 去 JFR 里 看 safepoint 事 件 重 点 关 注 是 否 有 大 量 偏 向 锁 撤 销 相 关 的 停 顿 。 这 是 一 个 很 容 易 被 忽 视 的 根 因 。6. 实战什么时候保留偏向锁什么时候该彻底关掉6.1 先判断你的 JVM 是否开了偏向锁在 讨 论 调 优 之 前 先 要 确 认 你 的 JDK 版 本 和 默 认 参 数 。 最 快 的 方 法 是 执 行 java -XX:PrintFlagsFinal -version | grep -i biased输 出 里 会 有UseBiasedLocking和BiasedLockingStartupDelay等 参 数 。 我 接 触 过 的 JDK 8 到 JDK 11 的 服 务 器 版 本 默 认 都 是 开 启 的 且 启 动 延 迟 为 4 秒 。 到 了 JDK 15 情 况 变 了 。JEP 374 将 偏 向 锁 标 记 为 废 弃 默 认 值 也 改 成 了 关 闭 。 官 方 给 出 的 理 由 很 直 白 偏 向 锁 的 维 护 成 本 高 撤 销 机 制 与 hashCode 、 GC 等 功 能 交 互 复 杂 而 且 在 现 代 服 务 器 环 境 下 大 量 应 用 的 锁 竞 争 模 式 已 经 变 得 更 激 烈 偏 向 锁 的 收 益 远 远 不 如 早 年 那 么 明 显 。 我 自 己 在 JDK 17 上 验 证 过 需 要 手 动 加-XX:UseBiasedLocking才 能 重 新 开 启 但 既 然 官 方 已 经 在 劝 退 我 不 太 建 议 在 新 项 目 里 特 意 去 开 它 。不 同 版 本 的 行 为 差 异 大 致 是 这 样 JDK 版 本默 认 状 态备 注JDK 6默 认 开 启引 入 偏 向 锁 后 续 版 本 增 加 4 秒 启 动 延 迟JDK 8 / 11默 认 开 启大 部 分 线 上 系 统 的 主 要 版 本JDK 15默 认 关 闭JEP 374 标 记 废 弃 需 手 动 开 启6.2 用 JOL 观察对象头的偏向状态如 果 想 看 一 个 对 象 的 实 际 锁 状 态 可 以 用 OpenJDK 的 JOL 工 具 。 在 项 目 里 引 入 jol-core 依 赖 然 后 写 一 段 很 简 单 的 代 码 public class MarkWordDemo { public static void main(String[] args) throws Exception { Object obj new Object(); System.out.println(ClassLayout.parseInstance(obj).toPrintable()); synchronized (obj) { System.out.println(ClassLayout.parseInstance(obj).toPrintable()); } } }在 JDK 8 上 跑 这 段 代 码 记 得 加-XX:BiasedLockingStartupDelay0去 掉 启 动 延 迟 你 会 在 锁 内 看 到 对 象 头 标 记 为 带 有 线 程 ID 的 偏 向 状 态 。 如 果 换 到 JDK 17 上 默 认 运 行 至 少 在 当 前 版 本 的 实 现 里 你 会 观 察 到 它 不 再 走 偏 向 路 径 。 JOL 是 我 平 时 验 证 锁 机 制 的 首 选 工 具 尤 其 是 想 看 清 对 象 头 里 每 个 bit 的 变 化 比 纯 靠 文 档 推 断 直 观 得 多 。6.3 场景判断留还是关结 合 我 自 己 的 实 践 我 会 用 下 面 这 张 表 做 决 策 场 景建 议理 由无 竞 争 或 极 低 竞 争 同 一 线 程 反 复 进 入 同 步 块保 留 偏 向 锁省 掉 反 复 CAS 收 益 最 明 显多 线 程 高 频 切 换 访 问 同 一 同 步 块关 闭 偏 向 锁撤 销 成 本 会 反 噬 性 能对 象 会 被 调 用 identityHashCode 或 放 入 IdentityHashMap关 闭 偏 向 锁这 类 对 象 本 就 无 法 偏 向 开 着 只 增 加 判 断 开 销服 务 器 上 JDK 15 以 上 且 无 专 门 压 测 数 据维 持 默 认 关 闭跟 随 官 方 默 认 值 减 少 不 确 定 性老 项 目 迁 移 到 新 JDK 后 锁 性 能 有 异 常用 参 数 对 照 测 试分 别 开 / 关 偏 向 锁 跑 压 测 用 数 据 说 话这 里 说 的 “ 关 闭 偏 向 锁 ” 其 实 就 是 加 一 个 启 动 参 数 -XX:-UseBiasedLocking而 对 于 确 实 想 保 留 偏 向 锁 的 场 景 常 见 的 组 合 是 -XX:UseBiasedLocking -XX:BiasedLockingStartupDelay0第 一 个 参 数 确 认 开 启 第 二 个 参 数 去 掉 启 动 延 迟 让 应 用 一 启 动 就 立 刻 处 于 偏 向 模 式 。 在 JDK 15 之 前 的 版 本 里 这 是 压 测 场 景 经 常 用 的 一 套 配 置 但 生 产 环 境 我 通 常 不 会 动 启 动 延 迟 默 认 4 秒 已 经 考 虑 到 了 启 动 阶 段 的 线 程 不 稳 定 性 。6.4 我的实操建议最 后 分 享 一 点 经 验 。 偏 向 锁 的 调 优 不 是 “ 开 了 就 快 、 关 了 就 慢 ” 这 么 简 单 它 的 收 益 完 全 取 决 于 你 的 并 发 模 型 。 我 一 般 会 先 用 JFR 或 者 压 测 工 具 数 据 说 话 而 不 是 凭 感 觉 调 参 数 。 如 果 同 步 块 的 竞 争 率 非 常 低 偏 向 锁 能 帮 你 省 掉 一 大 笔 原 子 操 作 的 开 销 如 果 你 的 业 务 有 多 线 程 经 常 交 替 访 问 同 一 批 对 象 那 关 掉 它 反 而 是 一 种 保 护 。我 在 实 际 项 目 里 遇 到 过 一 个 很 典 型 的 案 例 代 码 里 有 一 个 被 多 线 程 共 享 的 缓 存 对 象 读 多 写 少 但 读 的 线 程 是 轮 询 模 式 每 次 都 是 不 同 线 程 进 入 。 偏 向 锁 在 这 个 场 景 里 反 复 撤 销 最 终 触 发 批 量 撤 销 同 时 带 来 了 一 堆 safepoint 毛 刺 。 把-XX:-UseBiasedLocking加 上 之 后 虽 然 每 次 进 入 同 步 块 要 多 一 次 CAS 但 整 体 吞 吐 量 反 而 稳 了 句 号 。如 果 你 在 面 试 里 被 问 到 偏 向 锁 我 的 建 议 是 不 要 只 背 “ 无 竞 争 优 化 ” 这 句 话 。 能 说 清 Mark Word 的 位 复 用 、 撤 销 需 要 safepoint 、 批 量 重 偏 向 与 批 量 撤 销 的 阈 值 差 异 以 及 JDK 15 之 后 默 认 关 闭 的 原 因 才 是 真 正 理 解 了 这 个 “ 又 爱 又 恨 的 崽 ” 。
返回列表