并发

1.Synchronized 相关问题

  1. 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 实 现 , 也 就 是 三 种 不 同 的 锁 :  偏 向 锁 ( Biased Locking)  轻 量 级 锁  重 量 级 锁 这 三 种 锁 使 得 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 认 为 此 内 存 值 并 没 有 发 生 改 变 , 但 实 际 上 是 有 被 其 他 线 程 改 过 的 , 这 种 情 况 对 依 赖 过 程 值 的 情 景 的 运 算 结 果 影 响 很 大 。 解 决 的 思 路 是 引 入 版 本 号 , 每 次 变 量 更 新 都 把 版 本 号 加 一。

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

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

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

  2. 那么请谈谈 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 的 时 候 , 其 实 就 是 两 个 队 列 的 互 相 移 动 。

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

    ReentrantLock 是 Lock 的 实 现 类 , 是 一 个 互 斥 的 同 步 锁 。 从 功 能 角 度 , ReentrantLock 比 Synchronized 的 同 步 操 作 更 精 细 ( 因 为 可 以 像 普 通 对 象 一 样 使 用 ) , 甚 至 实 现 Synchronized 没 有 的 高 级 功 能 , 如 :  等 待 可 中 断 : 当 持 有 锁 的 线 程 长 期 不 释 放 锁 的 时 候 , 正 在 等 待 的 线 程 可 以 选 择 放 弃 等 待 , 对 处 理 执 行 时 间 非 常 长 的 同 步 块 很 有 用 。  带 超 时 的 获 取 锁 尝 试 : 在 指 定 的 时 间 范 围 内 获 取 锁 , 如 果 时 间 到 了 仍 然 无 法 获 取 则 返 回 。  可 以 判 断 是 否 有 线 程 在 排 队 等 待 获 取 锁 。  可 以 响 应 中 断 请 求 : 与 Synchronized 不 同 , 当 获 取 到 锁 的 线 程 被 中 断 时 , 能 够 响 应 中 断 , 中 断 异 常 将 会 被 抛 出 , 同 时 锁 会 被 释 放 。  可 以 实 现 公 平 锁 。 从 锁 释 放 角 度 , Synchronized 在 JVM 层 面 上 实 现 的 , 不 但 可 以 通 过 一 些 监 控 工 具 监 控 Synchronized 的 锁 定 , 而 且 在 代 码 执 行 出 现 异 常 时 , JVM 会 自 动 释 放 锁 定 ; 但 是 使 用 Lock 则 不 行 , Lock 是 通 过 代码 实 现 的 , 要 保 证 锁 定 一 定 会 被 释 放 , 就 必 须 将 unLock() 放 到 finally{} 中 。 从 性 能 角 度 , Synchronized 早 期 实 现 比 较 低 效 , 对 比 ReentrantLock, 大 多 数 场 景 性 能 都 相 差 较 大 。 但 是 在 Java 6 中 对 其 进 行 了 非 常 多 的 改 进 , 在 竞 争 不 激 烈 时 , Synchronized 的 性 能 要 优 于 ReetrantLock; 在 高 竞 争 情 况 下 , Synchronized 的 性 能 会 下 降 几 十 倍 , 但 是 ReetrantLock 的 性 能 能 维 持 常 态 。

  4. ReentrantLock 是如何实现可重入性的?

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

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

    通 常 所 说 的 并 发 包 ( JUC) 也 就 是 java.util.concurrent 及 其 子 包 , 集 中 了 Java 并 发 的 各 种 基 础 工 具 类 , 具 体 主 要 包 括 几 个 方 面 :  提 供 了 CountDownLatch、 CyclicBarrier、 Semaphore 等 , 比 Synchronized 更 加 高 级 , 可 以 实 现 更 加 丰 富 多 线 程 操 作 的 同 步 结 构 。  提 供 了 ConcurrentHashMap、 有 序 的 ConcunrrentSkipListMap, 或 者 通 过 类 似 快 照 机 制 实 现 线 程 安 全 的 动 态 数 组 CopyOnWriteArrayList 等 , 各 种 线 程 安 全 的 容 器 。 提 供 了 ArrayBlockingQueue、 SynchorousQueue 或 针 对 特 定 场 景 的 PriorityBlockingQueue 等 , 各 种 并 发 队 列 实 现 。  强 大 的 Executor 框 架 , 可 以 创 建 各 种 不 同 类 型 的 线 程 池 , 调 度 任 务 运 行 等 。

  6. 请谈谈 ReadWriteLock 和 StampedLock。

    虽 然 ReentrantLock 和 Synchronized 简 单 实 用 , 但 是 行 为 上 有 一 定 局 限 性 , 要 么 不 占 , 要 么 独 占 。 实 际 应 用 场 景 中 , 有 时 候 不 需 要 大 量 竞 争 的 写 操 作 , 而 是 以 并 发 读 取 为 主 , 为 了 进 一 步 优 化 并 发 操 作 的 粒 度 , Java 提 供 了 读 写 锁 。 读 写 锁 基 于 的 原 理 是 多 个 读 操 作 不 需 要 互 斥 , 如 果 读 锁 试 图 锁 定 时 , 写 锁 是 被 某 个 线 程 持 有 , 读 锁 将 无 法 获 得 , 而 只 好 等 待 对 方 操 作 结 束 , 这 样 就 可 以 自 动 保 证 不 会 读 取 到 有 争 议 的 数 据 。 ReadWriteLock 代 表 了 一 对 锁 , 下 面 是 一 个 基 于 读 写 锁 实 现 的 数 据 结 构 , 当 数 据 量 较 大 , 并 发 读 多 、 并 发 写 少 的 时 候 , 能 够 比 纯 同 步 版 本 凸 显 出 优 势 :

    读 写 锁 看 起 来 比 Synchronized 的 粒 度 似 乎 细 一 些 , 但 在 实 际 应 用 中 , 其 表 现 也 并 不 尽 如 人 意 , 主 要 还 是 因 为 相 对 比 较 大 的 开 销 。 所 以 , JDK 在 后 期 引 入 了 StampedLock, 在 提 供 类 似 读 写 锁 的 同 时 , 还 支 持 优 化 读 模 式 。 优 化 读 基 于 假 设 , 大 多 数 情 况 下 读 操 作 并 不 会 和 写 操 作 冲 突 , 其 逻 辑 是 先 试 着 修 改 , 然 后 通 过 validate 方 法 确 认 是 否 进 入 了 写 模 式 , 如 果 没 有 进 入 , 就 成 功 避 免 了 开 销 ; 如 果 进 入 , 则 尝 试 获 取 读 锁

  7. 如何让 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() 释 放 一 个 许 可 。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TEj4mxrR-1628238629373)(C:\Users\ykl\AppData\Roaming\Typora\typora-user-images\image-20210705190419151.png)]

    如 果 Semaphore 的 数 值 被 初 始 化 为 1, 那 么 一 个 线 程 就 可 以 通 过 acquire 进 入 互 斥 状 态 , 本 质 上 和 互 斥 锁 是 非 常 相 似 的 。 但 是 区 别 也 非 常 明 显 , 比 如 互 斥 锁 是 有 持 有 者 的 , 而 对 于 Semaphore 这 种 计 数 器 结 构 , 虽 然 有 类 似 功 能 , 但 其 实 不 存 在 真 正 意 义 的 持 有 者 , 除 非 我 们 进 行 扩 展 包 装

  8. 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 在 某 些 场 合 也 能 完 成 类 似 的 效 果 )

3.Java 线程池相关问题

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

    在 Java 中 , 所 谓 的 线 程 池 中 的 “ 线 程 ” , 其 实 是 被 抽 象 为 了 一 个 静 态 内 部 类 Worker, 它 基 于 AQS 实 现 , 存 放 在 线 程 池 的 HashSet workers 成 员 变 量 中 ;  而 需 要 执 行 的 任 务 则 存 放 在 成 员 变 量 workQueue ( BlockingQueue workQueue) 中 。 这 样 , 整 个 线 程 池 实 现 的 基 本 思 想 就 是 : 从 workQueue 中 不 断 取 出 需 要 执 行 的 任 务 , 放 在 Workers 中 进 行 处 理 。

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

    Java 中 的 线 程 池 的 创 建 其 实 非 常 灵 活 , 我 们 可 以 通 过 配 置 不 同 的 参 数 , 创 建 出 行 为 不 同 的 线 程 池 , 这 几 个 参 数 包 括 : corePoolSize: 线 程 池 的 核 心 线 程 数 。  maximumPoolSize: 线 程 池 允 许 的 最 大 线 程 数 。  keepAliveTime: 超 过 核 心 线 程 数 时 闲 置 线 程 的 存 活 时 间 。  workQueue: 任 务 执 行 前 保 存 任 务 的 队 列 , 保 存 由 execute 方 法 提 交 的 Runnable 任 务 。

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

    显 然 不 是 的 。 线 程 池 默 认 初 始 化 后 不 启 动 Worker, 等 待 有 请 求 时 才 启 动 。 每 当 我 们 调 用 execute() 方 法 添 加 一 个 任 务 时 , 线 程 池 会 做 如 下 判 断 :  如 果 正 在 运 行 的 线 程 数 量 小 于 corePoolSize, 那 么 马 上 创 建 线 程 运 行 这 个 任 务 ;  如 果 正 在 运 行 的 线 程 数 量 大 于 或 等 于 corePoolSize, 那 么 将 这 个 任 务 放 入 队 列 ;  如 果 这 时 候 队 列 满 了 , 而 且 正 在 运 行 的 线 程 数 量 小 于 maximumPoolSize, 那 么 还 是 要 创 建 非 核 心 线 程 立 刻 运 行 这 个 任 务 ;  如 果 队 列 满 了 , 而 且 正 在 运 行 的 线 程 数 量 大 于 或 等 于 maximumPoolSize, 那 么 线 程 池 会 抛 出 异 常 RejectExecutionException。当 一 个 线 程 完 成 任 务 时 , 它 会 从 队 列 中 取 下 一 个 任 务 来 执 行 。 当 一 个 线 程 无 事 可 做 , 超 过 一 定 的 时 间 ( keepAliveTime) 时 , 线 程 池 会 判 断 。 如 果 当 前 运 行 的 线 程 数 大 于 corePoolSize, 那 么 这 个 线 程 就 被 停 掉 。 所 以 线 程 池 的 所 有 任 务 完 成 后 , 它 最 终 会 收 缩 到 corePoolSize 的 大 小 。

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

    SingleThreadExecutor 线 程 池 这 个 线 程 池 只 有 一 个 核 心 线 程 在 工 作 , 也 就 是 相 当 于 单 线 程 串 行 执 行 所 有 任 务 。 如 果 这 个 唯 一 的 线 程 因 为 异 常 结 束 , 那 么 会 有 一 个 新 的 线 程 来 替 代 它 。 此 线 程 池 保 证 所 有 任 务 的 执 行 顺 序 按 照 任 务 的 提 交 顺 序 执 行 。  corePoolSize: 1, 只 有 一 个 核 心 线 程 在 工 作 。  maximumPoolSize: 1。  keepAliveTime: 0L。  workQueue: new LinkedBlockingQueue(), 其 缓 冲 队 列 是 无 界 的 。 2. FixedThreadPool 线 程 池 FixedThreadPool 是 固 定 大 小 的 线 程 池 , 只 有 核 心 线 程 。 每 次 提 交 一 个 任 务 就 创 建 一 个 线 程 , 直 到 线 程 达 到 线 程 池 的 最 大 大 小 。 线 程 池 的 大 小 一 旦 达 到 最 大 值 就 会 保 持 不 变 , 如 果 某 个 线 程 因 为 执 行 异 常 而 结 束 , 那 么 线 程 池 会 补 充 一 个 新 线 程 。FixedThreadPool 多 数 针 对 一 些 很 稳 定 很 固 定 的 正 规 并 发 线 程 , 多 用 于 服 务 器 。  corePoolSize: nThreads  maximumPoolSize: nThreads  keepAliveTime: 0L  workQueue: new LinkedBlockingQueue(), 其 缓 冲 队 列 是 无 界 的 。 3. CachedThreadPool 线 程 池 CachedThreadPool 是 无 界 线 程 池 , 如 果 线 程 池 的 大 小 超 过 了 处 理 任 务 所 需 要 的 线 程 , 那 么 就 会 回 收 部 分 空 闲 ( 60 秒 不 执 行 任 务 ) 线 程 , 当 任 务 数 增 加 时 , 此 线 程 池 又 可 以 智 能 的 添 加 新 线 程 来 处 理 任 务 。 线 程 池 大 小 完 全 依 赖 于 操 作 系 统 ( 或 者 说 JVM) 能 够 创 建 的 最 大 线 程 大 小 。 SynchronousQueue 是 一 个 是 缓 冲 区 为 1 的 阻 塞 队 列 。 缓 存 型 池 子 通 常 用 于 执 行 一 些 生 存 期 很 短 的 异 步 型 任 务 , 因 此 在 一 些 面 向 连 接 的 daemon 型 SERVER 中 用 得 不 多 。 但 对 于 生 存 期 短 的 异 步 任 务 , 它 是 Executor 的 首 选 。  corePoolSize: 0  maximumPoolSize: Integer.MAX_VALUE  keepAliveTime: 60L  workQueue: new SynchronousQueue(), 一 个 是 缓 冲 区 为 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 实 例 , 它 用 来 执 行 一 个 任 务

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-30DEhfef-1628238629373)(C:\Users\ykl\AppData\Roaming\Typora\typora-user-images\image-20210705190735431.png)]

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tRlDeNLH-1628238629374)(C:\Users\ykl\AppData\Roaming\Typora\typora-user-images\image-20210705190643864.png)]

4.Java 内存模型相关问题

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

    Java 的 内 存 模 型 定 义 了 程 序 中 各 个 变 量 的 访 问 规 则 , 即 在 虚 拟 机 中 将
    变 量 存 储 到 内 存 和 从 内 存 中 取 出 这 样 的 底 层 细 节 。
    此 处 的 变 量 包 括 实 例 字 段 、 静 态 字 段 和 构 成 数 组 对 象 的 元 素 , 但 是 不 包
    括 局 部 变 量 和 方 法 参 数 , 因 为 这 些 是 线 程 私 有 的 , 不 会 被 共 享 , 所 以 不
    存 在 竞 争 问 题 。
    Java 中 各 个 线 程 是 怎 么 彼 此 看 到 对 方 的 变 量 的 呢 ? Java 中 定 义 了 主 内
    存 与 工 作 内 存 的 概 念 :
    所 有 的 变 量 都 存 储 在 主 内 存 , 每 条 线 程 还 有 自 己 的 工 作 内 存 , 保 存 了 被
    该 线 程 使 用 到 的 变 量 的 主 内 存 副 本 拷 贝 。
    线 程 对 变 量 的 所 有 操 作 ( 读 取 、 赋 值 ) 都 必 须 在 工 作 内 存 中 进 行 , 不 能
    直 接 读 写 主 内 存 的 变 量 。 不 同 的 线 程 之 间 也 无 法 直 接 访 问 对 方 工 作 内 存
    的 变 量 , 线 程 间 变 量 值 的 传 递 需 要 通 过 主 内 存 。

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

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

    1. 保 证 此 变 量 对 所 有 线 程 的 可 见 性 。 当 一 条 线 程 修 改 了 这 个 变 量 的 值 , 新
      值 对 于 其 他 线 程 是 可 以 立 即 得 知 的 。 而 普 通 变 量 做 不 到 这 一 点 。
    2. 禁 止 指 令 重 排 序 优 化 。 普 通 变 量 仅 仅 能 保 证 在 该 方 法 执 行 过 程 中 , 得 到
      正 确 结 果 , 但 是 不 保 证 程 序 代 码 的 执 行 顺 序 。
      Java 的 内 存 模 型 定 义 了 8 种 内 存 间 操 作 :
      lock 和 unlock
       把 一 个 变 量 标 识 为 一 条 线 程 独 占 的 状 态 。
       把 一 个 处 于 锁 定 状 态 的 变 量 释 放 出 来 , 释 放 之 后 的 变 量 才 能 被 其 他 线 程
      锁 定 。
      read 和 write
       把 一 个 变 量 值 从 主 内 存 传 输 到 线 程 的 工 作 内 存 , 以 便 load。
       把 store 操 作 从 工 作 内 存 得 到 的 变 量 的 值 , 放 入 主 内 存 的 变 量 中 。
      load 和 store
       把 read 操 作 从 主 内 存 得 到 的 变 量 值 放 入 工 作 内 存 的 变 量 副 本 中 。
       把 工 作 内 存 的 变 量 值 传 送 到 主 内 存 , 以 便 write。
      use 和 assgin
       把 工 作 内 存 变 量 值 传 递 给 执 行 引 擎 。
       将 执 行 引 擎 值 传 递 给 工 作 内 存 变 量 值 。
      volatile 的 实 现 基 于 这 8 种 内 存 间 操 作 , 保 证 了 一 个 线 程 对 某 个
      volatile 变 量 的 修 改 , 一 定 会 被 另 一 个 线 程 看 见 , 即 保 证 了 可 见 性 。
  3. 既然 volatile 能够保证线程间的变量可见性,是不是就意味着基于 volatile 变量的运算就是并发安全的?

    不 是 的 。 基 于 volatile 变 量 的 运 算 在 并 发 下 不 一 定 是 安 全 的 。
    volatile 变 量 在 各 个 线 程 的 工 作 内 存 , 不 存 在 一 致 性 问 题 ( 各 个 线 程 的
    工 作 内 存 中 volatile 变 量 , 每 次 使 用 前 都 要 刷 新 到 主 内 存 ) 。
    但 是 Java 里 面 的 运 算 并 非 原 子 操 作 , 导 致 volatile 变 量 的 运 算 在 并
    发 下 一 样 是 不 安 全 的 。

  4. 请对比下 volatile 对比 Synchronized 的异同。

    Synchronized 既 能 保 证 可 见 性 , 又 能 保 证 原 子 性 , 而 volatile 只 能 保 证 可 见 性 , 无 法 保 证 原 子 性 。 ThreadLocal 和 Synchonized 都 用 于 解 决 多 线 程 并 发 访 问 , 防 止 任 务 在 共 享 资 源 上 产 生 冲 突 。 但 是 ThreadLocal 与 Synchronized 有 本 质 的 区 别 。 Synchronized 用 于 实 现 同 步 机 制 , 是 利 用 锁 的 机 制 使 变 量 或 代 码 块 在 某 一 时 该 只 能 被 一 个 线 程 访 问 , 是 一 种 “ 以 时 间 换 空 间 ” 的 方 式 。 而 ThreadLocal 为 每 一 个 线 程 都 提 供 了 变 量 的 副 本 , 使 得 每 个 线 程 在 某 一 时 间 访 问 到 的 并 不 是 同 一 个 对 象 , 根 除 了 对 变 量 的 共 享 , 是 一 种 “ 以 空 间 换 时 间 ” 的 方 式 。

  5. 请谈谈 ThreadLocal 是怎么解决并发安全的?

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

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

    使 用 ThreadLocal 要 注 意 remove! ThreadLocal 的 实 现 是 基 于 一 个 所 谓 的 ThreadLocalMap, 在 ThreadLocalMap 中 , 它 的 key 是 一 个 弱 引 用 。 通 常 弱 引 用 都 会 和 引 用 队 列 配 合 清 理 机 制 使 用 , 但 是 ThreadLocal 是 个 例 外 , 它 并 没 有 这 么 做 。 这 意 味 着 , 废 弃 项 目 的 回 收 依 赖 于 显 式 地 触 发 , 否 则 就 要 等 待 线 程 结 束 , 进 而 回 收 相 应 ThreadLocalMap! 这 就 是 很 多 OOM 的 来 源 , 所 以 通 常 都 会 建 议 , 应 用 一 定 要 自 己 负 责 remove, 并 且 不 要 和 线 程 池 配 合 , 因 为 worker 线 程 往 往 是 不 会 退 出 的

5.并发队列相关问题

  1. 谈下对基于链表的非阻塞无界队列 ConcurrentLinkedQueue 原理的理解?

  2. ConcurrentLinkedQueue 内部是如何使用 CAS 非阻塞算法来保证多线程下入队出队操作的线程安全?

  3. 基于链表的阻塞队列 LinkedBlockingQueue 原理。

  4. 阻塞队列LinkedBlockingQueue 内部是如何使用两个独占锁 ReentrantLock 以及对应的条件变量保证多线程先入队出队操作的线程安全?

  5. 为什么不使用一把锁,使用两把为何能提高并发度?

  6. 基于数组的阻塞队列 ArrayBlockingQueue 原理。

  7. ArrayBlockingQueue 内部如何基于一把独占锁以及对应的两个条件变量实现出入队操作的线程安全?

  8. 谈谈对无界优先级队列 PriorityBlockingQueue 原理?

  9. PriorityBlockingQueue 内部使用堆算法保证每次出队都是优先级最高的元素,元素入队时候是如何建堆的,元素出队后如何调整堆的平衡的?

Java基础 - 并发、锁相关推荐

  1. Java 多线程 并发 锁 Java线程面试题

    1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速.比如,如果一个线程完成 ...

  2. Java面试题-Java基础-并发编程

    目录 什么是线程? 并行和并发有什么区别? 线程和进程的区别?(进程程序)[θred] 守护线程是什么? 线程间通信? 创建线程有哪几种方式?并写代码实现? 说一下 runnable 和 callab ...

  3. Java多线程| 并发| 锁 深入学习

    主要内容 左转Java内存模型 右转AbstractQueuedSynchronizer 分析 后转StampedLock分析 * 线程概念 * 特性.上下文切换.线程状态 * 线程控制 * Thre ...

  4. Java基础-并发篇

    3.1. JAVA 并发知识库 3.2. JAVA 线程实现/创建方式 3.2.1. 继承 Thread 类 ​ Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例. ...

  5. java基础---悲观锁和乐观锁

    悲观锁: 悲观锁总是假设最坏的情况,每次拿数据都认为别人会修改数据,所以要加锁,别人只能等待,直到我释放锁才能拿到锁;数据库的行锁,表锁,写锁都是这种方式,java中的synchtorized和Ree ...

  6. java基础---对象锁和类锁的区别

    synchronized 加到 static 方法前面是给class 加锁,即类锁:而synchronized 加到非静态方法前面是给对象上锁. 对象锁和类锁是不同的锁,所以多个线程同时执行这2个不同 ...

  7. JAVA各种并发锁从synchronized 到CAS 到 AQS

    https://www.cnblogs.com/cyrbjh/p/12404794.html

  8. [Java基础]并发修改异常

  9. java中synchronized锁的升级(偏向锁、轻量级锁及重量级锁)

    java同步锁前置知识点 编码中如果使用锁可以使用synchronized关键字,对方法.代码块进行同步加锁 Synchronized同步锁是jvm内置的隐式锁(相对Lock,隐式加锁与释放) Syn ...

最新文章

  1. Python处理时间日期模块
  2. linux fls函数,linux常用操作命令
  3. ADO.NET 连接Access2007和Access2003
  4. Unity Shader基本例子
  5. Python入门很难吗? 为什么越来越多的人都学Python?
  6. war包热更新_基于IDEA热部署更新服务器Tomcat类,服务器Tomcat热更新
  7. SQLAlchemy engine.Connection
  8. 海龟交易法则05_掌握优势
  9. 我的开发笔记spring等常见问题
  10. L1-011. A-B-PAT团体程序设计天梯赛(GPLT)
  11. ubuntu16.04配置opencv2、python2、cuda8.0、cudnn以及caffe
  12. .Net 站点跨域问题及解决方法
  13. php spl自动加载类,php – SPL自动加载最佳实践
  14. Educational Codeforces Round 67
  15. 云南数据中心机房资源介绍、IDC资源分布,机房数据中心建设解决方案
  16. 《统计学》基础知识归纳
  17. python实现isprime函数_Python语言的isPrime函数 - python
  18. ASP.Net三层架构
  19. html video添加字幕,HTML5标签:video元素的使用方法及作用
  20. Arduino通过USB转TTL无BootLoader烧录程序的两种办法

热门文章

  1. 店铺怎么做基本的设置
  2. 梦想还是要有的,即使被摧残着!
  3. No URLs will be polled as dynamic configuration sources警告处理
  4. 移动增值业务随笔(2)
  5. 操作系统教程(第5版)习题解答
  6. php 微信接口文档例子,微信开发之群发(示例代码)
  7. Git简介、安装教程附安装包
  8. 估值 是什么意思。 怎么估值。
  9. 网络设备配置与管理————11、配置主机名、时钟、IP地址
  10. [BZOJ5020][THUWC 2017]在美妙的数学王国中畅游(LCT + 一点数学知识)