没有合适的资源?快使用搜索试试~ 我知道了~
并发面试专题
资源推荐
资源详情
资源评论
Synchronized 相关问题
问题一: Synchronized 用过吗, 其原理是什么?
这是一道 Java 面试中几乎百分百会问到的问题, 因为没有任何写过并发程序的开发者
会没听说或者没接触过 Synchronized。
Synchronized 是由 JVM 实现的一种实现互斥同步的一种方式, 如果你查看被
Synchronized 修饰过的程序块编译后的字节码, 会发现, 被 Synchronized 修饰过
的程序块, 在编译前后被编译器生成了monitorenter 和 monitorexit 两个字节码指令
。
这两个指令是什么意思呢?
在虚拟机执行到 monitorenter 指令时, 首先要尝试获取对象的锁: 如果这个对象没
有锁定, 或者当前线程已经拥有了这个对象的锁, 把锁
的 计 数 器 + 1 ; 当 执 行 monitorexit 指 令 时 将 锁 计 数 器 - 1 ; 当 计 数 器
为 0 时 , 锁 就 被 释 放 了 。
如果获取对象失败了, 那当前线程就要阻塞等待, 直到对象锁被另外一个线程释放为
止。
Java 中 Synchronize 通 过 在 对 象 头 设 置 标 记 , 达 到 了 获 取 锁 和 释 放
锁 的 目 的 。
问题二: 你刚才提到获取对象的锁, 这个“ 锁” 到底是什么? 如何确定对
象 的 锁 ?
“ 锁” 的本质其实是 monitorenter 和 monitorexit 字节码指令的一个 Reference
类型的参数, 即要锁定和解锁的对象。 我们知道, 使用
Synchronized 可以修饰不同的对象, 因此, 对应的对象锁可以这么确定。
1. 如果 Synchronized 明确 指定 了锁对象, 比 如 Synchronized( 变量
名) 、 Synchronized( this) 等, 说明加解锁对象为该对象。
2. 如 果 没 有 明 确 指 定 :
若 Synchronized 修饰的方法为非静态方法, 表示此方法对应的对象为锁对象;
若 Synchronized 修饰的方法为静态方法, 则表示此方法对应的类对象为锁对象。
注意, 当一个对象被锁住时, 对象里面所有用 Synchronized 修饰的方法都将产生
堵塞, 而对象里非 Synchronized 修饰的方法可正常被调用, 不受锁影响。
问题三: 什 么 是 可 重 入性 , 为 什 么 说 Synchronized 是 可 重 入 锁 ?
可 重 入 性 是 锁 的 一 个 基 本 要 求 , 是 为 了 解 决 自 己 锁 死 自 己 的 情 况 。 比
如 下面 的 伪代 码 , 一 个 类中 的 同 步方 法 调用 另 一 个同 步 方法 , 假如
Synchronized 不 支 持 重 入 , 进 入 method 2 方 法 时 当 前 线 程 获 得 锁 ,
method 2 方法 里面 执行 method 1 时 当 前 线 程 又 要去 尝试 获取 锁, 这 时
如果不支持重入, 它就要等释放, 把自己阻塞, 导致自己锁死自己。
· 点 击 图 片 , 放 大 查 看 ·
对 Synchronized 来说, 可重入性是显而易见的, 刚才提到, 在执行
monitorenter 指令时, 如果这个对象没有锁定, 或者当前线程已经拥
有了这个对象的锁( 而不是已拥有了锁则不能继续获取) , 就把锁的计数器 + 1 ,
其实本质上就通过这种方式实现了可重入性。
问题四: JVM 对 Java 的原生锁做了哪些优化?
在 Java 6 之 前 , Monitor 的 实 现 完 全 依 赖 底 层 操 作 系 统 的 互 斥 锁 来
实 现 , 也 就 是 我 们 刚 才 在 问 题 二 中 所 阐 述 的 获 取 / 释 放 锁 的 逻 辑 。
由 于 Java 层 面 的 线 程 与 操 作 系 统 的 原 生 线 程 有 映 射 关 系 , 如 果 要 将 一
个 线 程 进 行 阻 塞 或 唤 起 都 需 要 操 作 系 统 的 协 助 , 这 就 需 要 从 用 户 态 切 换
到 内 核 态 来 执 行 , 这 种 切 换 代 价 十 分 昂 贵 , 很 耗 处 理 器 时 间 , 现 代 JDK
中 做 了 大 量 的 优 化 。
一种优化是使用自旋锁, 即在把线程进行阻塞操作之前先让线程自旋等待一段时间,
可能在等待期间其他线程已经解锁, 这时就无需再让线程执行阻塞操作, 避免了用户
态到内核态的切换。
现代 JDK 中还提供了三种不同的 Monitor 实现, 也就是三种不同的锁:
� 偏 向 锁 ( Biased Locking)
� 轻 量 级 锁
� 重 量 级 锁
这 三 种 锁 使 得 JDK 得 以 优 化 Synchronized 的 运 行 , 当 JVM 检 测
到 不 同 的 竞 争 状 况 时 , 会 自 动 切 换 到 适 合 的 锁 实 现 , 这 就 是 锁 的 升 级 、
降 级 。
� 当 没 有 竞 争 出 现 时 , 默 认 会 使 用 偏 向 锁 。
JVM 会 利 用 CAS 操 作 , 在 对 象 头 上 的 Mark Word 部 分 设 置 线 程
ID, 以 表 示 这 个 对 象 偏 向 于 当 前 线 程 , 所 以 并 不 涉 及 真 正 的 互 斥 锁 , 因
为 在 很 多 应 用 场 景 中 , 大 部 分 对 象 生 命 周 期 中 最 多 会 被 一 个 线 程 锁 定 ,
使 用 偏 斜 锁 可 以 降 低 无 竞 争 开 销 。
� 如 果 有 另 一 线 程 试 图 锁 定 某 个 被 偏 斜 过 的 对 象 , JVM 就 撤 销 偏 斜 锁 ,
切 换 到 轻 量 级 锁 实 现 。
� 轻 量 级 锁 依 赖 CAS 操作 Mark Word 来 试 图 获 取 锁 , 如 果 重 试 成 功 , 就
使用 普通 的轻量 级锁 ; 否则 , 进 一步 升级 为重 量级锁。
问题五: 为什么说 Synchronized 是非公平锁?
非公平主要表现在获取锁的行为上, 并非是按照申请锁的时间前后给等待线程分配锁
的, 每当锁被释放后, 任何一个线程都有机会竞争到锁, 这样做的目的是为了提高
执行性能, 缺点是可能会产生线程饥饿现象。问题六: 什么是锁消除和锁粗化?
� 锁消除 : 指虚拟机 即时编译器在运行时, 对一些代码上 要求同步, 但被检
测 到 不 可 能 存 在 共 享 数 据 竞 争 的 锁 进 行 消 除 。 主 要 根 据 逃 逸 分 析 。 程 序
员 怎 么 会 在 明 知 道 不 存 在 数 据 竞 争 的 情 况 下 使 用 同 步 呢 ? 很 多 不 是 程 序
员 自 己 加 入 的 。
� 锁 粗化 : 原 则上 , 同 步块 的 作用 范围 要 尽量 小。 但是 如果 一 系列 的连续 操
作 都 对 同 一 个 对 象 反 复 加 锁 和 解 锁 , 甚 至 加 锁 操 作 在 循 环 体 内 , 频 繁 地
进 行 互 斥 同 步 操 作 也 会 导 致 不 必 要 的 性 能 损 耗 。
锁粗化就是增大锁的作用域。
剩余23页未读,继续阅读
资源评论
蚁库
- 粉丝: 31
- 资源: 99
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功