Synchronized 相 关 问 题

1: Synchronized 用 过 吗 , 其 原 理 是 什 么 ?

这 是 一 道 Java 面 试 中 几 乎 百 分 百 会 问 到 的 问 题 , 因 为 没 有 任 何 写 过 并 发 程 序 的 开 发 者 会 没 听 说 或 者 没 接 触 过 Synchronized。

Synchronized 是 由 JVM 实 现 的 一 种 实 现 互 斥 同 步 的 一 种 方 式 , 如 果你 查 看 被 Synchronized 修 饰 过 的 程 序 块 编 译 后 的 字 节 码 , 会 发 现 , 被 Synchronized 修 饰 过 的 程 序 块 , 在 编 译 前 后 被 编 译 器 生 成 了 monitorenter 和 monitorexit 两 个 字 节 码 指 令 。

这 两 个 指 令 是 什 么 意 思 呢 ?

在 虚 拟 机 执 行 到 monitorenter 指 令 时 , 首 先 要 尝 试 获 取 对 象 的 锁 :

如 果 这 个 对 象 没 有 锁 定 , 或 者 当 前 线 程 已 经 拥 有 了 这 个 对 象 的 锁 , 把 锁 的 计 数 器 +1; 当 执 行 monitorexit 指 令 时 将 锁 计 数 器 -1; 当 计 数 器 为 0 时 , 锁 就 被 释 放 了 。

如 果 获 取 对 象 失 败 了 , 那 当 前 线 程 就 要 阻 塞 等 待 , 直 到 对 象 锁 被 另 外 一 个 线 程 释 放 为 止 。 Java 中Synchronize 通 过 在 对 象 头 设 置 标 记 , 达 到 了 获 取 锁 和 释 放 锁 的 目 的 。

2: 你 刚 才 提 到 获 取 对 象 的 锁 , 这 个 “ 锁 ” 到 底 是 什 么 ? 如 何 确 定 对 象 的 锁 ?

“ 锁 ” 的 本 质 其 实 是 monitorenter 和 monitorexit 字 节 码 指 令 的 一 个 Reference 类 型 的 参 数 , 即 要 锁 定 和 解 锁 的 对 象 。 我 们 知 道 , 使 用Synchronized 可 以 修 饰 不 同 的 对 象 , 因 此 , 对 应 的 对 象 锁 可 以 这 么 确 定 。

1. 如 果 Synchronized 明 确 指 定 了 锁 对 象 , 比 如 Synchronized( 变 量 名 ) 、 Synchronized(this) 等 , 说 明 加 解 锁 对 象 为 该 对 象 。

2. 如 果 没 有 明 确 指 定 : 若 Synchronized 修 饰 的 方 法 为 非 静 态 方 法 , 表 示 此 方 法 对 应 的 对 象 为 锁 对 象 ; 若 Synchronized 修 饰 的 方 法 为 静 态 方 法 , 则 表 示 此 方 法 对 应 的 类 对 象 为 锁 对 象 。 注 意 , 当 一 个 对 象 被 锁 住 时 , 对 象 里 面 所 有 用 Synchronized 修 饰 的 方 法 都 将 产 生 堵 塞 , 而 对 象 里 非 Synchronized 修 饰 的 方 法 可 正 常 被 调 用 , 不 受 锁 影 响 。

3: 什 么 是 可 重 入 性 , 为 什 么 说 Synchronized 是 可 重 入 锁 ?

可 重 入 性 是 锁 的 一 个 基 本 要 求 , 是 为 了 解 决 自 己 锁 死 自 己 的 情 况 。 比 如 下 面 的 伪 代 码 , 一 个 类 中 的 同 步 方 法 调 用 另 一 个 同 步 方 法 , 假 如 Synchronized 不 支 持 重 入 , 进 入 method2 方 法 时 当 前 线 程 获 得 锁 ,method2 方 法 里 面 执 行 method1 时 当 前 线 程 又 要 去 尝 试 获 取 锁 , 这 时 如 果 不 支 持 重 入 , 它 就 要 等 释 放 , 把 自 己 阻 塞 , 导 致 自 己 锁 死 自 己 。

对 Synchronized 来 说 , 可 重 入 性 是 显 而 易 见 的 , 刚 才 提 到 , 在 执 行 monitorenter 指 令 时 , 如 果 这 个 对 象 没 有 锁 定 , 或 者 当 前 线 程 已 经 拥有 了 这 个 对 象 的 锁 ( 而 不 是 已 拥 有 了 锁 则 不 能 继 续 获 取 ) , 就 把 锁 的 计 数 器 +1, 其 实 本 质 上 就 通 过 这 种 方 式 实 现 了 可 重 入 性 。

4 : JVM 对 Java 的 原 生 锁 做 了 哪 些 优 化 ?

在 Java 6 之 前 , Monitor 的 实 现 完 全 依 赖 底 层 操 作 系 统 的 互 斥 锁 来 实 现 , 也 就 是 我 们 刚 才 在 问 题 二 中 所 阐 述 的 获 取 /释 放 锁 的 逻 辑 。 由 于 Java 层 面 的 线 程 与 操 作 系 统 的 原 生 线 程 有 映 射 关 系 , 如 果 要 将 一 个 线 程 进 行 阻 塞 或 唤 起 都 需 要 操 作 系 统 的 协 助 , 这 就 需 要 从 用 户 态 切 换 到 内 核 态 来 执 行 , 这 种 切 换 代 价 十 分 昂 贵 , 很 耗 处 理 器 时 间 , 现 代 JDK 中 做 了 大 量 的 优 化 。

一 种 优 化 是 使 用 自 旋 锁 , 即 在 把 线 程 进 行 阻 塞 操 作 之 前 先 让 线程 自 旋 等 待 一 段 时 间 , 可 能 在 等 待 期 间 其 他 线 程 已 经 解 锁 , 这 时 就 无 需 再 让 线 程 执 行 阻 塞 操 作 , 避 免 了 用 户 态 到 内 核 态 的 切 换 。

现 代 JDK 中 还 提 供 了 三 种 不 同 的 Monitor 实 现 , 也 就 是 三 种 不 同 的 锁 :

  1. 偏 向 锁
  2. 轻 量 级 锁
  3. 重 量 级 锁

这 三 种 锁 使 得 JDK 得 以 优 化 Synchronized 的 运 行 , 当 JVM 检 测 到 不 同 的 竞 争 状 况 时 , 会 自 动 切 换 到 适 合 的 锁 实 现 , 这 就 是 锁 的 升 级 、 降 级 。

当 没 有 竞 争 出 现 时 , 默 认 会 使 用 偏 向 锁 。JVM 会 利 用 CAS 操 作 , 在 对 象 头 上 的 Mark Word 部 分 设 置 线 程 ID, 以 表 示 这 个 对 象 偏 向 于 当 前 线 程 , 所 以 并 不 涉 及 真 正 的 互 斥 锁 , 因 为 在 很 多 应 用 场 景 中 , 大 部 分 对 象 生 命 周 期 中 最 多 会 被 一 个 线 程 锁 定 , 使 用 偏 斜 锁 可 以 降 低 无 竞 争 开 销 。

如 果 有 另 一 线 程 试 图 锁 定 某 个 被 偏 斜 过 的 对 象 , JVM 就 撤 销 偏 斜 锁 , 切 换 到 轻 量 级 锁 实 现 。 轻 量 级 锁 依 赖 CAS 操 作 Mark Word 来 试 图 获 取 锁 , 如 果 重 试 成 功 , 就 使 用 普 通 的 轻 量 级 锁 ; 否 则 , 进 一 步 升 级 为 重 量 级 锁 。

5: 为 什 么 说 Synchronized 是 非 公 平 锁 ?

非 公 平 主 要 表 现 在 获 取 锁 的 行 为 上 , 并 非 是 按 照 申 请 锁 的 时 间 前 后 给 等 待 线 程 分 配 锁 的 , 每 当 锁 被 释 放 后 , 任 何 一 个 线 程 都 有 机 会 竞 争 到 锁 , 这 样 做 的 目 的 是 为 了 提 高 执 行 性 能 , 缺 点 是 可 能 会 产 生 线 程 饥 饿 现 象 。

6 : 什 么 是 锁 消 除 和 锁 粗 化 ?

锁 消 除 : 指 虚 拟 机 即 时 编 译 器 在 运 行 时 , 对 一 些 代 码 上 要 求 同 步 , 但 被 检 测 到 不 可 能 存 在 共 享 数 据 竞 争 的 锁 进 行 消 除 。 主 要 根 据 逃 逸 分 析 。

程 序 员 怎 么 会 在 明 知 道 不 存 在 数 据 竞 争 的 情 况 下 使 用 同 步 呢 ?

很 多 不 是 程 序 员 自 己 加 入 的 。 锁 粗 化 : 原 则 上 , 同 步 块 的 作 用 范 围 要 尽 量 小 。 但 是 如 果 一 系 列 的 连 续 操 作 都 对 同 一 个 对 象 反 复 加 锁 和 解 锁 , 甚 至 加 锁 操 作 在 循 环 体 内 , 频 繁 地 进 行 互 斥 同 步 操 作 也 会 导 致 不 必 要 的 性 能 损 耗 。

锁 粗 化 就 是 增 大 锁 的 作 用 域 。

7: 为 什 么 说 Synchronized 是 一 个 悲 观 锁 ? 乐 观 锁 的 实 现 原 理 又 是 什 么 ? 什 么 是 CAS, 它 有 什 么 特 性 ?

Synchronized 显 然 是 一 个 悲 观 锁 , 因 为 它 的 并 发 策 略 是 悲 观 的 :

不 管 是 否 会 产 生 竞 争 , 任 何 的 数 据 操 作 都 必 须 要 加 锁 、 用 户 态 核 心 态 转 换 、 维 护 锁 计 数 器 和 检 查 是 否 有 被 阻 塞 的 线 程 需 要 被 唤 醒 等 操 作 。 随 着 硬 件 指 令 集 的 发 展 , 我 们 可 以 使 用 基 于 冲 突 检 测 的 乐 观 并 发 策 略 。 先 进 行 操 作 , 如 果 没 有 其 他 线 程 征 用 数 据 , 那 操 作 就 成 功 了 ;

如 果 共 享 数 据 有 征 用 , 产 生 了 冲 突 , 那 就 再 进 行 其 他 的 补 偿 措 施 。这 种 乐 观 的 并 发 策 略 的 许 多 实 现 不 需 要 线 程 挂 起 , 所 以 被 称 为 非 阻 塞 同 步 。

乐 观 锁 的 核 心 算 法 是 CAS( Compareand Swap, 比 较 并 交 换 ) , 它 涉 及 到 三 个 操 作 数 : 内 存 值 、 预 期 值 、 新 值 。 当 且 仅 当 预 期 值 和 内 存 值 相 等 时 才 将 内 存 值 修 改 为 新 值 。 这 样 处 理 的 逻 辑 是 , 首 先 检 查 某 块 内 存 的 值 是 否 跟 之 前 我 读 取 时 的 一 样 , 如 不 一 样 则 表 示 期 间 此 内 存 值 已 经 被 别 的 线 程 更 改 过 , 舍 弃 本 次 操 作 , 否 则 说 明 期 间 没 有 其 他 线 程 对 此 内 存 值 操 作 , 可 以 把 新 值 设 置 给 此 块 内 存 。

CAS 具 有 原 子 性 , 它 的 原 子 性 由 CPU 硬 件 指 令 实 现 保 证 , 即 使 用 JNI 调 用 Native 方 法 调 用 由 C++ 编 写 的 硬 件 级 别 指 令 , JDK 中 提 供 了 Unsafe 类 执 行 这 些 操 作 。

8: 乐 观 锁 一 定 就 是 好 的 吗 ?

乐 观 锁 避 免 了 悲 观 锁 独 占 对 象 的 现 象 , 同 时 也 提 高 了 并 发 性 能 , 但 它 也 有 缺 点 :

1. 乐 观 锁 只 能 保 证 一 个 共 享 变 量 的 原 子 操 作 。 如 果 多 一 个 或 几 个 变 量 , 乐 观 锁 将 变 得 力 不 从 心 , 但 互 斥 锁 能 轻 易 解 决 , 不 管 对 象 数 量 多 少 及 对 象 颗 粒 度 大 小 。

2. 长 时 间 自 旋 可 能 导 致 开 销 大 。 假 如 CAS 长 时 间 不 成 功 而 一 直 自 旋 , 会 给 CPU 带 来 很 大 的 开 销 。

3. ABA 问 题 。 CAS 的 核 心 思 想 是 通 过 比 对 内 存 值 与 预 期 值 是 否一 样 而 判 断 内 存 值 是 否 被 改 过 , 但 这 个 判 断 逻 辑 不 严 谨 , 假 如 内 存 值 原 来 是 A, 后 来 被 一 条 线 程 改 为 B, 最 后 又 被 改 成 了 A, 则 CAS 认 为 此 内 存 值 并 没 有 发 生 改 变 , 但 实 际 上 是 有 被 其 他 线 程 改 过 的 , 这 种 情 况 对 依 赖 过 程 值 的 情 景 的 运 算 结 果 影 响 很 大 。 解 决 的 思 路 是 引 入 版 本 号 , 每 次 变 量 更 新 都 把 版 本 号 加 一 。

可 重 入 锁 ReentrantLock 及 其 他 显 式 锁 相 关 问 题

9 : 跟 Synchronized 相 比 , 可 重 入 锁 ReentrantLock 其 实 现 原 理 有 什 么 不 同 ?

其 实 , 锁 的 实 现 原 理 基 本 是 为 了 达 到 一 个 目 的 : 让 所 有 的 线 程 都 能 看 到 某 种 标 记 。 Synchronized 通 过 在 对 象 头 中 设 置 标 记 实 现 了这 一 目 的 , 是 一 种 JVM 原 生 的 锁 实 现 方 式 , 而 ReentrantLock 以 及 所 有 的 基 于 Lock 接 口 的 实 现 类 , 都 是 通 过 用 一 个 volitile 修 饰 的 int 型 变 量 , 并 保 证 每 个 线 程 都 能 拥 有 对 该 int 的 可 见 性 和 原 子 修 改 , 其 本 质 是 基 于 所 谓 的 AQS 框 架 。

10 : 那 么 请 谈 谈 AQS 框 架 是 怎 么 回 事 儿 ?

AQS( AbstractQueuedSynchronizer 类 ) 是 一 个 用 来 构 建 锁 和 同 步 器的 框 架 , 各 种 Lock 包 中 的 锁 ( 常 用 的 有 ReentrantLock、 ReadWriteLock) , 以 及 其 他 如 Semaphore、 CountDownLatch, 甚 至 是 早 期 的 FutureTask 等 , 都 是 基 于 AQS 来 构 建 。

1. AQS 在 内 部 定 义 了 一 个 volatile int state 变 量 , 表 示 同 步 状 态 : 当 线 程 调 用 lock 方 法 时 , 如 果 state=0, 说 明 没 有 任 何 线 程 占 有 共 享 资 源 的 锁 , 可 以 获 得 锁 并 将 state=1; 如 果 state=1, 则 说 明 有 线 程 目 前 正 在 使 用 共 享 变 量 , 其 他 线 程 必 须 加 入 同 步 队 列 进 行 等 待 。

2. AQS 通 过 Node 内 部 类 构 成 的 一 个 双 向 链 表 结 构 的 同 步 队 列 , 来 完 成 线 程 获 取 锁 的 排 队 工 作 , 当 有 线 程 获 取 锁 失 败 后 , 就 被 添 加 到 队 列 末 尾 。

o Node 类 是 对 要 访 问 同 步 代 码 的 线 程 的 封 装 , 包 含 了 线 程 本 身 及 其 状 态 叫 waitStatus( 有 五 种 不 同 取 值 , 分 别 表 示 是 否 被 阻 塞 , 是 否 等 待 唤 醒 , 是 否 已 经 被 取 消 等 ) , 每 个 Node 结 点 关 联 其 prev 结 点 和 next 结 点 , 方 便 线 程 释 放 锁 后 快 速 唤 醒 下 一 个 在 等 待 的 线 程 , 是 一 个 FIFO 的 过 程 。

o Node 类 有 两 个 常 量 , SHARED 和 EXCLUSIVE, 分 别 代 表 共 享 模 式 和 独占 模 式 。 所 谓 共 享 模 式 是 一 个 锁 允 许 多 条 线 程 同 时 操 作 ( 信 号 量 Semaphore 就 是 基 于 AQS 的 共 享 模 式 实 现 的 ) , 独 占 模 式 是 同 一 个 时 间 段 只 能 有 一 个 线 程 对 共 享 资 源 进 行 操 作 , 多 余 的 请 求 线 程 需 要 排 队 等 待 ( 如 ReentranLock) 。

3. AQS 通 过 内 部 类 ConditionObject 构 建 等 待 队 列 ( 可 有 多 个 ) , 当 Condition 调 用 wait() 方 法 后 , 线 程 将 会 加 入 等 待 队 列 中 , 而 当Condition 调 用 signal() 方 法 后 , 线 程 将 从 等 待 队 列 转 移 动 同 步 队 列 中 进 行 锁 竞 争 。

4. AQS 和 Condition 各 自 维 护 了 不 同 的 队 列 , 在 使 用 Lock 和 Condition 的 时 候 , 其 实 就 是 两 个 队 列 的 互 相 移 动 。

11 : 请 尽 可 能 详 尽 地 对 比 下 Synchronized 和 ReentrantLock 的 异 同 。

ReentrantLock 是 Lock 的 实 现 类 , 是 一 个 互 斥 的 同 步 锁 。

从 功 能 角 度 , ReentrantLock 比 Synchronized 的 同 步 操 作 更 精 细 ( 因 为 可 以 像 普 通 对 象 一 样 使 用 ) , 甚 至 实 现 Synchronized 没 有 的 高 级 功 能 , 如 : 等 待 可 中 断 : 当 持 有 锁 的 线 程 长 期 不 释 放 锁 的 时 候 , 正 在 等 待 的 线 程 可 以 选 择 放 弃 等 待 , 对 处 理 执 行 时 间 非 常 长 的 同 步 块 很 有 用 。

带 超 时 的 获 取 锁 尝 试 : 在 指 定 的 时 间 范 围 内 获 取 锁 , 如 果 时 间 到 了 仍 然 无 法 获 取 则 返 回 。 可 以 判 断 是 否 有 线 程 在 排 队 等 待 获 取 锁 。

可 以 响 应 中 断 请 求 : 与 Synchronized 不 同 , 当 获 取 到 锁 的 线 程 被 中断 时 , 能 够 响 应 中 断 , 中 断 异 常 将 会 被 抛 出 , 同 时 锁 会 被 释 放 。

可 以 实 现 公 平 锁 。 从 锁 释 放 角 度 , Synchronized 在 JVM 层 面 上 实 现 的 , 不 但 可 以 通 过 一 些 监 控 工 具 监 控 Synchronized 的 锁 定 , 而 且 在 代 码 执 行 出 现 异 常 时 , JVM 会 自 动 释 放 锁 定 ; 但 是 使 用 Lock 则 不 行 , Lock 是 通 过 代码 实 现 的 , 要 保 证 锁 定 一 定 会 被 释 放 , 就 必 须 将 unLock() 放 到 finally{} 中 。

从 性 能 角 度 , Synchronized 早 期 实 现 比 较 低 效 , 对 比 ReentrantLock, 大 多 数 场 景 性 能 都 相 差 较 大 。 但 是 在 Java 6 中 对 其 进 行 了 非 常 多 的 改 进 , 在 竞 争 不 激 烈 时 , Synchronized 的 性 能 要 优 于 ReetrantLock; 在 高 竞 争 情 况 下 , Synchronized 的 性 能 会 下 降 几 十 倍 , 但 是 ReetrantLock 的 性 能 能 维 持 常 态 。

12 : ReentrantLock 是 如 何 实 现 可 重 入 性 的 ?

ReentrantLock 内 部 自 定 义 了 同 步 器 Sync( Sync 既 实 现 了 AQS, 又 实 现 了 AOS, 而 AOS 提 供 了 一 种 互 斥 锁 持 有 的 方 式 ) , 其 实 就 是 加 锁 的 时 候 通 过 CAS 算 法 , 将 线 程 对 象 放 到 一 个 双 向 链 表 中 , 每 次 获 取 锁 的 时 候 , 看 下 当 前 维 护 的 那 个 线 程 ID 和 当 前 请 求 的 线 程 ID 是 否 一 样 , 一 样 就 可 重 入 了 。

13 : 除 了 ReetrantLock, 你 还 接 触 过 JUC 中 的 哪 些 并 发 工 具 ?

通 常 所 说 的 并 发 包 ( JUC) 也 就 是 java.util.concurrent 及 其 子 包 , 集 中 了 Java 并 发 的 各 种 基 础 工 具 类 , 具 体 主 要 包 括 几 个 方 面 :

提 供 了 CountDownLatch、 CyclicBarrier、 Semaphore 等 , 比 Synchronized 更 加 高 级 , 可 以 实 现 更 加 丰 富 多 线 程 操 作 的 同 步 结 构 。

提 供 了 ConcurrentHashMap、 有 序 的 ConcunrrentSkipListMap, 或 者 通 过 类 似 快 照 机 制 实 现 线 程 安 全 的 动 态 数 组 CopyOnWriteArrayList 等 , 各 种 线 程 安 全 的 容 器 。

提 供 了 ArrayBlockingQueue、 SynchorousQueue 或 针 对 特 定 场 景 的 PriorityBlockingQueue 等 ,各 种 并 发 队 列 实 现 。

强 大 的 Executor 框 架 , 可 以 创 建 各 种 不 同 类 型 的 线 程 池 , 调 度 任 务 运 行 等 。

14 : 请 谈 谈 ReadWriteLock 和 StampedLock。

虽 然 ReentrantLock 和 Synchronized 简 单 实 用 , 但 是 行 为 上 有 一 定 局 限 性 , 要 么 不 占 , 要 么 独 占 。 实 际 应 用 场 景 中 , 有 时 候 不 需 要 大 量 竞 争 的 写 操 作 , 而 是 以 并 发 读 取 为 主 , 为 了 进 一 步 优 化 并 发 操 作 的 粒 度 , Java 提 供 了 读 写 锁 。

读 写 锁 基 于 的 原 理 是 多 个 读 操 作 不 需 要 互 斥 , 如 果 读 锁 试 图 锁 定 时 , 写 锁 是 被 某 个 线 程 持 有 , 读 锁 将 无 法 获 得 , 而 只 好 等 待 对 方 操 作 结 束 , 这 样 就 可 以 自 动 保 证 不 会 读 取 到 有 争 议 的 数 据 。 ReadWriteLock 代 表 了 一 对 锁 , 下 面 是 一 个 基 于 读 写 锁 实 现 的 数 据 结 构 , 当 数 据 量 较 大 , 并 发 读 多 、 并 发 写 少 的 时 候 , 能 够 比 纯 同 步 版 本 凸 显 出 优 势 :

读 写 锁 看 起 来 比 Synchronized 的 粒 度 似 乎 细 一 些 , 但 在 实 际 应 用 中 , 其 表 现 也 并 不 尽 如 人 意 , 主 要 还 是 因 为 相 对 比 较 大 的 开 销 。

所 以 , JDK 在 后 期 引 入 了 StampedLock, 在 提 供 类 似 读 写 锁 的 同 时 , 还 支 持 优 化 读 模 式 。 优 化 读 基 于 假 设 , 大 多 数 情 况 下 读 操 作 并 不 会 和 写 操 作 冲 突 , 其 逻 辑 是 先 试 着 修 改 , 然 后 通 过 validate 方 法 确 认 是 否 进 入 了 写 模 式 , 如 果 没 有 进 入 , 就 成 功 避 免 了 开 销 ; 如 果 进 入 , 则 尝 试 获 取 读 锁 。

15 : 如 何 让 Java 的 线 程 彼 此 同 步 ? 你 了 解 过 哪 些 同 步 器 ?

请 分 别 介 绍 下 。

JUC 中 的 同 步 器 三 个 主 要 的 成 员 : CountDownLatch、 CyclicBarrier 和 Semaphore, 通 过 它 们 可 以 方 便 地 实 现 很 多 线 程 之 间 协 作 的 功 能 。 CountDownLatch 叫 倒 计 数 , 允 许 一 个 或 多 个 线 程 等 待 某 些 操 作 完 成 。

看 几 个 场 景 :

跑 步 比 赛 , 裁 判 需 要 等 到 所 有 的 运 动 员 ( “ 其 他 线 程 ” ) 都 跑 到 终 点 ( 达 到 目 标 ) , 才 能 去 算 排 名 和 颁 奖 。

模 拟 并 发 , 我 需 要 启 动 100 个 线 程 去 同 时 访 问 某 一 个 地 址 , 我 希 望 它 们 能 同 时 并 发 , 而 不 是 一 个 一 个 的 去 执 行 。

用 法 : CountDownLatch 构 造 方 法 指 明 计 数 数 量 , 被 等 待 线 程 调 用 countDown 将 计 数 器 减 1, 等 待 线 程 使 用 await 进 行 线 程 等 待 。

一 个 简 单 的 例 子 :

CyclicBarrier 叫 循 环 栅 栏 , 它 实 现 让 一 组 线 程 等 待 至 某 个 状 态 之 后 再 全 部 同 时 执 行 , 而 且 当 所 有 等 待 线 程 被 释 放 后 , CyclicBarrier 可 以 被 重 复 使 用 。 CyclicBarrier 的 典 型 应 用 场 景 是 用 来 等 待 并 发 线 程 结 束 。

CyclicBarrier 的 主 要 方 法 是 await(), await() 每 被 调 用 一 次 , 计 数 便 会 减 少 1, 并 阻 塞 住 当 前 线 程 。 当 计 数 减 至 0 时 , 阻 塞 解 除 , 所 有 在 此 CyclicBarrier 上 面 阻 塞 的 线 程 开 始 运 行 。 在 这 之 后 , 如 果 再 次 调 用 await(), 计 数 就 又 会 变 成 N-1, 新 一 轮 重 新 开 始 , 这 便 是 Cyclic 的 含 义 所 在 。 CyclicBarrier.await() 带 有 返 回 值 , 用 来 表 示 当 前 线 程 是 第 几 个 到 达 这 个 Barrier 的 线 程 。

举 例 说 明 如 下 :

Semaphore, Java 版 本 的 信 号 量 实 现 , 用 于 控 制 同 时 访 问 的 线 程 个 数 , 来 达 到 限 制 通 用 资 源 访 问 的 目 的 , 其 原 理 是 通 过 acquire() 获 取 一 个 许 可 , 如 果 没 有 就 等 待 , 而 release() 释 放 一 个 许 可 。如 果 Semaphore 的 数 值 被 初 始 化 为 1, 那 么 一 个 线 程 就 可 以 通 过 acquire 进 入 互 斥 状 态 , 本 质 上 和 互 斥 锁 是 非 常 相 似 的 。 但 是 区 别 也 非 常 明 显 , 比 如 互 斥 锁 是 有 持 有 者 的 , 而 对 于 Semaphore 这 种 计 数 器 结 构 , 虽 然 有 类 似 功 能 , 但 其 实 不 存 在 真 正 意 义 的 持 有 者 , 除 非 我 们 进 行 扩 展 包 装 。

16 : CyclicBarrier 和 CountDownLatch 看 起 来 很 相 似 , 请 对 比 下 呢 ?

它 们 的 行 为 有 一 定 相 似 度 , 区 别 主 要 在 于 :  CountDownLatch 是 不 可 以 重 置 的 , 所 以 无 法 重 用 ,CyclicBarrier 没 有 这 种 限 制 , 可 以 重 用 。

CountDownLatch 的 基 本 操 作 组 合 是 countDown/await, 调 用 await 的 线 程 阻 塞 等 待 countDown 足 够 的 次 数 , 不 管 你 是 在 一 个 线程 还 是 多 个 线 程 里 countDown, 只 要 次 数 足 够 即 可 。

CyclicBarrier 的 基 本 操 作 组 合 就 是 await, 当 所 有 的 伙 伴 都 调 用 了 await, 才 会 继 续 进 行 任 务 , 并 自 动 进 行 重 置 。

CountDownLatch 目 的 是 让 一 个 线 程 等 待 其 他 N 个 线 程 达 到 某 个 条 件 后 , 自 己 再 去 做 某 个 事 ( 通 过 CyclicBarrier 的 第 二 个 构 造 方 法 public CyclicBarrier(int parties, Runnable barrierAction), 在 新 线 程 里 做 事 可 以 达 到 同 样 的 效 果 ) 。 而 CyclicBarrier 的 目 的 是 让 N 多 线 程 互 相 等 待 直 到 所 有 的 都 达 到 某 个 状 态 , 然 后 这 N 个 线 程 再 继 续 执 行 各 自 后 续 ( 通 过 CountDownLatch 在 某 些 场 合 也 能 完 成 类 似 的 效 果 ) 。

Java 线 程 池 相 关 问 题

1 : Java 中 的 线 程 池 是 如 何 实 现 的 ?

在 Java 中 , 所 谓 的 线 程 池 中 的 “ 线 程 ” , 其 实 是 被 抽 象 为 了 一 个 静 态 内 部 类 Worker, 它 基 于 AQS 实 现 , 存 放 在 线 程 池 的 HashSet<Worker> workers 成 员 变 量 中 ; 而 需 要 执 行 的 任 务 则 存 放 在 成 员 变 量 workQueue ( BlockingQueue<Runnable> workQueue) 中 。

这 样 , 整 个 线 程 池 实 现 的 基 本 思 想 就 是 : 从 workQueue 中 不 断 取 出 需 要 执 行 的 任 务 , 放 在 Workers 中 进 行 处 理 。

2: 创 建 线 程 池 的 几 个 核 心 构 造 参 数 ?

Java 中 的 线 程 池 的 创 建 其 实 非 常 灵 活 , 我 们 可 以 通 过 配 置 不 同 的 参 数 , 创 建 出 行 为 不 同 的 线 程 池 , 这 几 个 参 数 包 括 :

corePoolSize: 线 程 池 的 核 心 线 程 数 。

maximumPoolSize: 线 程 池 允 许 的 最 大 线 程 数 。

keepAliveTime: 超 过 核 心 线 程 数 时 闲 置 线 程 的 存 活 时 间 。

workQueue: 任 务 执 行 前 保 存 任 务 的 队 列 , 保 存 由 execute 方 法 提 交 的 Runnable 任 务 。

3: 线 程 池 中 的 线 程 是 怎 么 创 建 的 ?是 一 开 始 就 随 着 线 程 池 的 启 动 创 建 好 的 吗 ?

显 然 不 是 的 。 线 程 池 默 认 初 始 化 后 不 启 动 Worker, 等 待 有 请 求 时 才 启 动 。 每 当 我 们 调 用 execute() 方 法 添 加 一 个 任 务 时 , 线 程 池 会 做 如 下 判 断 :

如 果 正 在 运 行 的 线 程 数 量 小 于 corePoolSize, 那 么 马 上 创 建 线 程 运 行 这 个 任 务 ; 如 果 正 在 运 行 的 线 程 数 量 大 于 或 等 于 corePoolSize, 那 么 将 这 个 任 务 放 入 队 列 ;

如 果 这 时 候 队 列 满 了 , 而 且 正 在 运 行 的 线 程 数 量 小 于 maximumPoolSize, 那 么 还 是 要 创 建 非 核 心 线 程 立 刻 运 行 这 个 任 务 ;

如 果 队 列 满 了 , 而 且 正 在 运 行 的 线 程 数 量 大 于 或 等 于 maximumPoolSize, 那 么 线 程 池 会 抛 出 异 常RejectExecutionException。当 一 个 线 程 完 成 任 务 时 , 它 会 从 队 列 中 取 下 一 个 任 务 来 执 行 。 当 一 个 线 程 无 事 可 做 , 超 过 一 定 的 时 间 ( keepAliveTime) 时 , 线 程 池 会 判 断 。

如 果 当 前 运 行 的 线 程 数 大 于 corePoolSize, 那 么 这 个 线 程 就 被 停 掉 。 所 以 线 程 池 的 所 有 任 务 完 成 后 , 它 最 终 会 收 缩 到 corePoolSize 的 大 小 。

4: 既 然 提 到 可 以 通 过 配 置 不 同 参 数 创 建 出 不 同 的 线 程 池 , 那 么 Java 中 默 认 实 现 好 的 线 程 池 又 有 哪 些 呢 ? 请 比 较 它 们 的 异 同 。

1. SingleThreadExecutor 线 程 池 这 个 线 程 池 只 有 一 个 核 心 线 程 在 工 作 , 也 就 是 相 当 于 单 线 程 串 行 执 行 所 有 任 务 。 如 果 这 个 唯 一 的 线 程 因 为 异 常 结 束 , 那 么 会 有 一 个 新 的 线 程 来 替 代 它 。 此 线 程 池 保 证 所 有 任 务 的 执 行 顺 序 按 照 任 务 的 提 交 顺 序 执 行 。

corePoolSize: 1, 只 有 一 个 核 心 线 程 在 工 作 。

maximumPoolSize: 1。

keepAliveTime: 0L。

workQueue: new LinkedBlockingQueue<Runnable>(), 其 缓 冲 队 列 是 无 界 的 。

2. FixedThreadPool 线 程 池

FixedThreadPool 是 固 定 大 小 的 线 程 池 , 只 有 核 心 线 程 。 每 次 提 交 一 个 任 务 就 创 建 一 个 线 程 , 直 到 线 程 达 到 线 程 池 的 最 大 大 小 。 线 程 池 的 大 小 一 旦 达 到 最 大 值 就 会 保 持 不 变 , 如 果 某 个 线 程 因 为 执 行 异 常 而 结 束 , 那 么 线 程 池 会 补 充 一 个 新 线 程 。FixedThreadPool 多 数 针 对 一 些 很 稳 定 很 固 定 的 正 规 并 发 线 程 , 多 用 于 服 务 器 。

corePoolSize: nThreads

maximumPoolSize: nThreads

keepAliveTime: 0L

workQueue: new LinkedBlockingQueue<Runnable>(), 其 缓 冲 队 列 是 无 界 的 。

3.CachedThreadPool 线 程 池 CachedThreadPool 是 无 界 线 程 池 , 如 果 线 程 池 的 大 小 超 过 了 处 理 任 务 所 需 要 的 线 程 , 那 么 就 会 回 收 部 分 空 闲 ( 60 秒 不 执 行 任 务 ) 线 程 , 当 任 务 数 增 加 时 , 此 线 程 池 又 可 以 智 能 的 添 加 新 线 程 来 处 理 任 务 。

线 程 池 大 小 完 全 依 赖 于 操 作 系 统 ( 或 者 说 JVM) 能 够 创 建 的 最 大 线 程 大 小 。 SynchronousQueue 是 一 个 是 缓 冲 区 为 1 的 阻 塞 队 列 。

缓 存 型 池 子 通 常 用 于 执 行 一 些 生 存 期 很 短 的 异 步 型 任 务 , 因 此 在 一 些 面 向 连 接 的 daemon 型 SERVER 中 用 得 不 多 。 但 对 于 生 存 期 短 的 异 步 任 务 , 它 是 Executor 的 首 选 。

corePoolSize: 0

maximumPoolSize: Integer.MAX_VALUE

keepAliveTime: 60L

workQueue: new SynchronousQueue<Runnable>(), 一 个 是 缓 冲 区 为 1 的 阻 塞 队 列 。

4.ScheduledThreadPool 线 程 池ScheduledThreadPool: 核 心 线 程 池 固 定 , 大 小 无 限 的 线 程 池 。 此 线 程 池 支 持 定 时 以 及 周 期 性 执 行 任 务 的 需 求 。

创 建 一 个 周 期 性 执 行 任 务 的 线 程 池 。 如 果 闲 置 , 非 核 心 线 程 池 会 在 DEFAULT_KEEPALIVEMILLIS 时间 内 回 收 。

corePoolSize: corePoolSize

maximumPoolSize: Integer.MAX_VALUE

keepAliveTime: DEFAULT_KEEPALIVE_MILLIS

workQueue: new DelayedWorkQueue()

5 : 如 何 在 Java 线 程 池 中 提 交 线 程 ?

线 程 池 最 常 用 的 提 交 任 务 的 方 法 有 两 种 :

1. execute(): ExecutorService.execute 方 法 接 收 一 个 Runable 实 例 , 它 用 来 执 行 一 个 任 务 :

2. submit(): ExecutorService.submit() 方 法 返 回 的 是 Future 对 象 。 可 以 用 isDone() 来 查 询 Future 是 否 已 经 完 成 , 当 任 务 完 成 时 , 它 具 有 一 个 结 果 , 可 以 调 用 get() 来 获 取 结 果 。 也 可 以 不 用 isDone() 进 行 检 查 就 直 接 调 用 get(), 在 这 种 情 况 下 , get() 将 阻 塞 , 直 至 结 果 准 备 就 绪 。

Java 内 存 模 型 相 关 问 题

6: 什 么 是 Java 的 内 存 模 型 , Java 中 各 个 线 程 是 怎 么 彼 此 看 到 对 方 的 变 量 的 ?

Java 的 内 存 模 型 定 义 了 程 序 中 各 个 变 量 的 访 问 规 则 , 即 在 虚 拟 机 中 将 变 量 存 储 到 内 存 和 从 内 存 中 取 出 这 样 的 底 层 细 节 。 此 处 的 变 量 包 括 实 例 字 段 、 静 态 字 段 和 构 成 数 组 对 象 的 元 素 , 但 是 不 包 括 局 部 变 量 和 方 法 参 数 , 因 为 这 些 是 线 程 私 有 的 , 不 会 被 共 享 , 所 以 不 存 在 竞 争 问 题 。

Java 中 各 个 线 程 是 怎 么 彼 此 看 到 对 方 的 变 量 的 呢 ?

Java 中 定 义 了 主 内 存 与 工 作 内 存 的 概 念 : 所 有 的 变 量 都 存 储 在 主 内 存 , 每 条 线 程 还 有 自 己 的 工 作 内 存 , 保 存 了 被 该 线 程 使 用 到 的 变 量 的 主 内 存 副 本 拷 贝 。

线 程 对 变 量 的 所 有 操 作 ( 读 取 、 赋 值 ) 都 必 须 在 工 作 内 存 中 进 行 , 不 能 直 接 读 写 主 内 存 的 变 量 。 不 同 的 线 程 之 间 也 无 法 直 接 访 问 对 方 工 作 内 存 的 变 量 , 线 程 间 变 量 值 的 传 递 需 要 通 过 主 内 存 。

7 : 请 谈 谈 volatile 有 什 么 特 点 , 为 什 么 它 能 保 证 变 量 对 所 有 线 程 的 可 见 性 ?

关 键 字 volatile 是 Java 虚 拟 机 提 供 的 最 轻 量 级 的 同 步 机 制 。 当 一 个 变 量 被 定 义 成 volatile 之 后 , 具 备 两 种 特 性 :

1.保 证 此 变 量 对 所 有 线 程 的 可 见 性 。 当 一 条 线 程 修 改 了 这 个 变 量 的 值 , 新 值 对 于 其 他 线 程 是 可 以 立 即 得 知 的 。 而 普 通 变 量 做 不 到 这 一 点 。

2. 禁 止 指 令 重 排 序 优 化 。 普 通 变 量 仅 仅 能 保 证 在 该 方 法 执 行 过 程 中 , 得 到 正 确 结 果 , 但 是 不 保 证 程 序 代 码 的 执 行 顺 序 。

Java 的 内 存 模 型 定 义 了 8 种 内 存 间 操 作 : lock 和 unlock 把 一 个 变 量 标 识 为 一 条 线 程 独 占 的 状 态 。

把 一 个 处 于 锁 定 状 态 的 变 量 释 放 出 来 , 释 放 之 后 的 变 量 才 能 被 其 他 线 程 锁 定 。 read 和 write 把 一 个 变 量 值 从 主 内 存 传 输 到 线 程 的 工 作 内 存 , 以 便 load。 把 store 操 作 从 工 作 内 存 得 到 的 变 量 的 值 , 放 入 主 内 存 的 变 量 中 。

load 和 store 把 read 操 作 从 主 内 存 得 到 的 变 量 值 放 入 工 作 内 存 的 变 量 副 本 中 。

把 工 作 内 存 的 变 量 值 传 送 到 主 内 存 , 以 便 write。 use 和 assgin

把 工 作 内 存 变 量 值 传 递 给 执 行 引 擎 。 将 执 行 引 擎 值 传 递 给 工 作 内 存 变 量 值 。 volatile 的 实 现 基 于 这 8 种 内 存 间 操 作 , 保 证 了 一 个 线 程 对 某 个 volatile 变 量 的 修 改 , 一 定 会 被 另 一 个 线 程 看 见 , 即 保 证 了 可 见 性 。

8 : 既 然 volatile 能 够 保 证 线 程 间 的 变 量 可 见 性 , 是 不 是 就 意 味 着 基 于 volatile 变 量 的 运 算 就 是 并 发 安 全 的 ?

显 然 不 是 的 。 基 于 volatile 变 量 的 运 算 在 并 发 下 不 一 定 是 安 全 的 。

volatile 变 量 在 各 个 线 程 的 工 作 内 存 , 不 存 在 一 致 性 问 题 ( 各 个 线 程 的 工 作 内 存 中 volatile 变 量 , 每 次 使 用 前 都 要 刷 新 到 主 内 存 ) 。

但 是 Java 里 面 的 运 算 并 非 原 子 操 作 , 导 致 volatile 变 量 的 运 算 在 并 发 下 一 样 是 不 安 全 的 。

9 : 请 对 比 下 volatile 对 比 Synchronized 的 异 同 。

Synchronized 既 能 保 证 可 见 性 , 又 能 保 证 原 子 性 , 而 volatile 只 能保 证 可 见 性 , 无 法 保 证 原 子 性 。

ThreadLocal 和 Synchonized 都 用 于 解 决 多 线 程 并 发 访 问 , 防 止 任 务 在 共 享 资 源 上 产 生 冲 突 。 但 是 ThreadLocal 与 Synchronized 有 本 质 的 区 别 。

Synchronized 用 于 实 现 同 步 机 制 , 是 利 用 锁 的 机 制 使 变 量 或 代 码 块 在 某 一 时 该 只 能 被 一 个 线 程 访 问 , 是 一 种 “ 以 时 间 换 空 间 ” 的 方 式 。 而 ThreadLocal 为 每 一 个 线 程 都 提 供 了 变 量 的 副 本 , 使 得 每 个 线 程 在 某 一 时 间 访 问 到 的 并 不 是 同 一 个 对 象 , 根 除 了 对 变 量 的 共 享 , 是 一 种 “ 以 空 间 换 时 间 ” 的 方 式 。

10: 请 谈 谈 ThreadLocal 是 怎 么 解 决 并 发 安 全 的 ?

ThreadLocal 这 是 Java 提 供 的 一 种 保 存 线 程 私 有 信 息 的 机 制 , 因 为 其 在 整 个 线 程 生 命 周 期 内 有 效 , 所 以 可 以 方 便 地 在 一 个 线 程 关 联 的 不 同 业 务 模 块 之 间 传 递 信 息 , 比 如 事 务 ID、 Cookie 等 上 下 文 相 关 信 息 。ThreadLocal 为 每 一 个 线 程 维 护 变 量 的 副 本 , 把 共 享 数 据 的 可 见 范 围 限 制 在 同 一 个 线 程 之 内 , 其 实 现 原 理 是 , 在 ThreadLocal 类 中 有 一 个 Map, 用 于 存 储 每 一 个 线 程 的 变 量 的 副 本 。

11 : 很 多 人 都 说 要 慎 用 ThreadLocal, 谈 谈 你 的 理 解 , 使 用 ThreadLocal 需 要 注 意 些 什 么 ?

使 用 ThreadLocal 要 注 意 remove! ThreadLocal 的 实 现 是 基 于 一 个 所 谓 的 ThreadLocalMap, 在 ThreadLocalMap 中 , 它 的 key 是 一 个 弱 引 用 。

通 常 弱 引 用 都 会 和 引 用 队 列 配 合 清 理 机 制 使 用 , 但 是 ThreadLocal 是 个 例 外 , 它 并 没 有 这 么 做 。

这 意 味 着 , 废 弃 项 目 的 回 收 依 赖 于 显 式 地 触 发 , 否 则 就 要 等 待 线 程 结 束 , 进 而 回 收 相 应 hreadLocalMap! 这 就 是 很 多 OOM 的 来 源 ,

所 以 通 常 都 会 建 议 , 应 用 一 定 要 自 己 负 责 remove, 并 且 不 要 和 线 程 池 配

Java线程相关综合问题

1:现在有 T1、T2、T3 三个线程,你怎样保证 T2 在 T1 执行完后执行,T3 在 T2 执行完后执 行?

这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟 悉。这个多线程问题比较简单,可以用 join 方法实现。

2:在 Java 中 Lock 接口比 synchronized 块的优势是什么?

你需要实现一个高效的缓存,它允 许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它?

lock 接口在多线程和并发编程中最大的优势是它们为读和写分别提供了锁,它能满足你写 像 ConcurrentHashMap 这样的高性能数据结构和有条件的阻塞。Java 线程面试的问题越来 越会根据面试者的回答来提问。我强烈建议在你去参加多线程的面试之前认真读一下 Locks,因为当前其大量用于构建电子交易终统的客户端缓存和交易连接空间。

3:在 java 中 wait 和 sleep 方法的不同?

通常会在电话面试中经常被问到的 Java 线程面试问题。最大的不同是在等待时 wait 会释放 锁,而 sleep 一直持有锁。Wait 通常被用于线程间交互,sleep 通常被用于暂停执行。

4:用 Java 实现阻塞队列

这是一个相对艰难的多线程面试问题,它能达到很多的目的。

第一,它可以检测侯选者是 否能实际的用 Java 线程写程序;

第二,可以检测侯选者对并发场景的理解,并且你可以根 据这个问很多问题。如果他用 wait()和 notify()方法来实现阻塞队列,你可以要求他用最新 的 Java 5 中的并发类来再写一次。

5:用 Java 写代码来解决生产者

——消费者问题。 与上面的问题很类似,但这个问题更经典,有些时候面试都会问下面的问题。在 Java 中怎 么解决生产者

——消费者问题,当然有很多解决方法,一种用阻塞队列实现的方法。有些时候他们甚至会问怎么实现哲学家进餐问题。

6:用 Java 编程一个会导致死锁的程序,你将怎么解决?

这是我最喜欢的 Java 线程面试问题,因为即使死锁问题在写多线程并发程序时非常普遍,但是很多侯选者并不能写 deadlock free code(无死锁代码?),他们很挣扎。只要告诉他 们,你有 N 个资源和 N 个线程,并且你需要所有的资源来完成一个操作。为了简单这里的 n 可以替换为 2,越大的数据会使问题看起来更复杂。通过避免 Java 中的死锁来得到关于 死锁的更多信息。

7: 什么是原子操作,Java 中的原子操作是什么?

非常简单的 java 线程面试问题,接下来的问题是你需要同步一个原子操作。

8:Java 中的 volatile 关键是什么作用?怎样使用它?在 Java 中它跟 synchronized 方法有什 么不同?

自从 Java 5 和 Java 内存模型改变以后,基于 volatile 关键字的线程问题越来越流行。应该 :准备好回答关于 volatile 变量怎样在并发环境中确保可见性。

9: 什么是竞争条件?你怎样发现和解决竞争?

这是一道出现在多线程面试的高级阶段的问题。大多数的面试官会问最近你遇到的竞争条件,以及你是怎么解决的。有些时间他们会写简单的代码,然后让你检测出代码的竞争条件。

在我看来这是最好的 java 线程面试 问题之一,它可以确切的检测候选者解决竞争条件的经验,or writing code which is free of data race or anyother race condition。关于这方面最好的书是《Concurrency practices in Java》。

10:你将如何使用 threaddump?你将如何分析 Thread dump?

在 UNIX 中你可以使用 kill -3,然后 thread dump 将会打印日志,在 windows 中你可以使用”CTRL+Break”。非常简单和专业的线程面试问题,但是如果他问你怎样分析它,就会很棘手。

11:为什么我们调用 start()方法时会执行 run()方法,为什么我们不能直接调用 run()方法?

这是另一个非常经典的 java 多线程面试问题。这也是我刚开始写线程程序时候的困惑。现在这个问题通常在电话面试或者是在初中级 Java 面试的第一轮被问到。这个问题的回答应该是这样的,当你调用 start()方法时你将创建新的线程,并且执行在 run()方法里的代码。

但是如果你直接调用 run()方法,它不会创建新的线程也不会执行调用线程的代码。

12:Java 中你怎样唤醒: 一个阻塞的线程?

这是个关于线程和阻塞的棘手的问题,它有很多解决方法。如果线程遇到了 IO 阻塞,我并且不认为有一种方法可以中止线程。如果线程因为调用 wait()、sleep()、或者 join()方法而导致的阻塞,你可以中断线程,并且通过抛出 InterruptedException 来唤醒它。

13:在 Java 中 CycliBarriar 和 CountdownLatch 有什么区别?

这个线程问题主要用来检测你是否熟悉 JDK5 中的并发包。这两个的区别是 CyclicBarrier 可 以重复使用已经通过的障碍,而 CountdownLatch 不能重复使用。

14:什么是不可变对象,它对写并发应用有什么帮助?

另一个多线程经典面试问题,并不直接跟线程有关,但间接帮助很多。这个 java 面试问题可以变的非常棘手,如果他要求你写一个不可变对象,或者问你为什么 String 是不可变 的。

15:你在多线程环境中遇到的常见的问题是什么?你是怎么解决它的?

多线程和并发程序中常遇到的有 Memory-interface、竞争条件、死锁、活锁和饥饿。问题 是没有止境的,如果你弄错了,将很难发现和调试。这是大多数基于面试的,而不是基于实际应用的 Java 线程问题。

并发编程面试汇总(2020)相关推荐

  1. 手撸架构,并发编程 面试123问

    技术栈 传送门 JAVA 基础 手撸架构,Java基础面试100问_vincent-CSDN博客 JAVA 集合 手撸架构,JAVA集合面试60问_vincent-CSDN博客 JVM 虚拟机 手撸架 ...

  2. java并发编程面试题_阿里常用Java并发编程面试试题总结

    一.概念 什么是线程 一个线程要执行任务,必须得有线程一个进程(程序)的所有任务都在线程中执行的一个线程执行任务是串行的,也就是说一个线程,同一时间内,只能执行一个任务 多线程原理 同一时间,CPU只 ...

  3. 并发编程面试宝典(内含69道常问面试题及答案解析)

    一.开篇: 众所周知,在Java的知识体系中,并发编程是非常重要的一环,也是面试的必问题,一个好的Java程序员是必须对并发编程这块有所了解的. 因此,大家不难发现 Java 并发问题一直是各个大厂面 ...

  4. 【2022】多线程并发编程面试真题

    文章目录 4. 多线程 4.1 创建线程有哪几种方式? 4.2 说说Thread类的常用方法 4.3 run()和start()有什么区别? 4.4 线程是否可以重复启动,会有什么后果? 4.5 介绍 ...

  5. 网络编程面试汇总(C++)

    网络编程(金山) 1. 简述Tcp三次握手和四次挥手.(金山WPS) 看我的文章:握手挥手详解 2. 基本I/O模型了解多少.(金山WPS) 游双<高性能服务器编程>第八章8.3节,p12 ...

  6. java并发编程面试

    文章目录 1.为什么要使用线程池? 2.你们哪些地方会使用到线程池? 3.线程池有哪些作用? 4.线程池的创建方式? 5.线程池底层是如何实现复用的? 6.ThreadPoolExecutor 核心参 ...

  7. 并发编程——JUC并发大厂面试问题

    摘要 现如今,不管是应届毕业生还是工作了三五年之内的工程师,在面试招聘的时候JUC并发编程的是必须掌握的一个技能,否者你将会被面试官玩弄.本博文将整理有关于的JUC的大厂面试问题和答案.帮助大家在面试 ...

  8. Java并发编程学习 + 原理分析(建议收藏)

    总结不易,如果对你有帮助,请点赞关注支持一下 微信搜索程序dunk,关注公众号,获取博客源码 Doug Lea是一个无私的人,他深知分享知识和分享苹果是不一样的,苹果会越分越少,而自己的知识并不会因为 ...

  9. java 并发框架源码_某网Java并发编程高阶技术-高性能并发框架源码解析与实战(云盘下载)...

    第1章 课程介绍(Java并发编程进阶课程) 什么是Disruptor?它一个高性能的异步处理框架,号称"单线程每秒可处理600W个订单"的神器,本课程目标:彻底精通一个如此优秀的 ...

最新文章

  1. Python——阶段总结(一)
  2. python修改电脑名称_修改计算机名称
  3. J-Link驱动下载和JLINK下载Hex程序
  4. VTK:网格之AddCell
  5. ubuntu命令安装中文语言包_win10之linux子系统ubuntu安装中文包(三)
  6. springBoot整合Dubbo使用与采坑
  7. 通过surfer提取边界bln文件的方法
  8. 全国大学生数学建模竞赛——2017A题(学习笔记)
  9. 微信公众号第三方平台授权流程
  10. CAD2016 画直线时第二点为相对坐标(相对第一个点的坐标),非绝对坐标
  11. 台式计算机可以连接手机WiFi么,台式机能连wifi吗
  12. Clickhouse 时间日期函数实战总结
  13. Allegro焊盘种类
  14. GRE隧道配置实验(静态路由)
  15. 计算球体重量:已知铁的比重是7.86(克/立方厘米),金的比重是19.3(克/立方厘米)。写一个程序,分别计算出给定直径的铁球与金球的质量。
  16. 2022-2028年中国LED灯珠行业竞争格局分析及投资发展研究报告
  17. 基于野狗优化算法的函数寻优算法
  18. Highmaps上海地区地图数据JSON格式
  19. Outlook或Foxmail发送邮件退信问题
  20. 给自己的软件制作注册码

热门文章

  1. 轮廓线DP(插头DP 裸 经典骨牌)
  2. 【转】微信小游戏开发总结
  3. 6009. 【THUWC2019模拟2019.1.18】Counting
  4. 学seo要知道什么代码
  5. 丝印印唛颜色实在、立体感强
  6. LPA* 路径搜索算法介绍及完整代码
  7. SteamVR 2.x UGUI交互系统(7)
  8. 2021全球与中国视频编辑软件市场现状及未来发展趋势
  9. 用python写一个下载器
  10. bootstrap dialog自行控制窗口的关闭