常⻅的锁策略的相关⾯试题
常⻅的锁策略的相关⾯试题
- 相关⾯试题
- 1. 你是怎么理解乐观锁和悲观锁的,具体怎么实现呢?
- 2. 介绍下读写锁?
- 3. 什么是⾃旋锁,为什么要使⽤⾃旋锁策略呢,缺点是什么?
- 4. synchronized 是可重⼊锁么?
- synchronized
- 锁升级
- 锁消除
- 锁粗化
相关⾯试题
1. 你是怎么理解乐观锁和悲观锁的,具体怎么实现呢?
悲观锁认为多个线程访问同⼀个共享变量冲突的概率较⼤, 会在每次访问共享变量之前都去真正加锁.
乐观锁认为多个线程访问同⼀个共享变量冲突的概率不⼤. 并不会真的加锁, ⽽是直接尝试访问数据. 在访问的同时识别当前的数据是否出现访问冲突.
悲观锁的实现就是先加锁(⽐如借助操作系统提供的 mutex), 获取到锁再操作数据. 获取不到锁就等待.
乐观锁的实现可以引⼊⼀个版本号. 借助版本号识别出当前的数据访问是否冲突. (实现细节参考上⾯的图).
2. 介绍下读写锁?
读写锁就是把读操作和写操作分别进⾏加锁.
读锁和读锁之间不互斥.
写锁和写锁之间互斥.
写锁和读锁之间互斥.
读写锁最主要⽤在 “频繁读, 不频繁写” 的场景中.
3. 什么是⾃旋锁,为什么要使⽤⾃旋锁策略呢,缺点是什么?
如果获取锁失败, ⽴即再尝试获取锁, ⽆限循环, 直到获取到锁为⽌. 第⼀次获取锁失败, 第⼆次的尝试会在极短的时间内到来. ⼀旦锁被其他线程释放, 就能第⼀时间获取到锁.
相⽐于挂起等待锁,
优点: 没有放弃 CPU 资源, ⼀旦锁被释放就能第⼀时间获取到锁, 更⾼效. 在锁持有时间⽐较短的场景下⾮常有⽤.
缺点: 如果锁的持有时间较⻓, 就会浪费 CPU 资源.
4. synchronized 是可重⼊锁么?
是可重⼊锁.
可重⼊锁指的就是连续两次加锁不会导致死锁.
实现的⽅式是在锁中记录该锁持有的线程⾝份, 以及⼀个计数器(记录加锁次数). 如果发现当前加锁的线程就是持有锁的线程, 则直接计数⾃增.
synchronized
上述"锁策略"就是名词解释,针对这些词,有一个概念上的认识即可
面试官进一步延伸问,一般还是基于某个特定的锁(synchronized)
原则上说, 回答问题的时候,越细越好!! 面试官问 1,你能回答出3,最合适的!!
synchronized 内部的工作原理
synchronized 背后涉及到了很多的"优化手段"
锁升级
synchronized 的加锁过程,尤其是"自适应"是咋回事
当线程执行到 synchronized 的时候,如果这个对象当前处于未加锁的状态, 就会经历以下过程~~
- 偏向锁阶段
- 轻量级锁阶段
- 重量级锁阶段
此处锁 只能 升级,不能降级.自适应这个词,严格的说不算很严谨
不可考~~ 保不齐未来某个版本就能降级了
锁消除
也是 synchronized 中内置的优化策略
编译器优化的一种方式.编译器编译代码的时候,如果发现这个代码,不需要加锁,就会自动把锁给干掉
锁粗化
会把多个细粒度的锁,合并成一个粗粒度的锁
synchronized { } 大括号里 包含的代码越少,就认为锁的粒度越细;包含的代码越多,就认为锁的粒度越粗
通常情况下,是更偏好于让锁的粒度细一些,更有利于多个线程并发执行的~~ 但是有的时候,是希望锁的粒度粗点也挺好
小结:
synchronized 背后涉及到了很多的"优化手段"