[JAVAEE] 面试题(一) - 锁策略, synchronized的详细介绍

目录

[一. 锁策略](#一. 锁策略)

[1.1 什么是锁策略](#1.1 什么是锁策略)

[1.2 悲观锁 vs 乐观锁 (加锁时遇到的场景)](#1.2 悲观锁 vs 乐观锁 (加锁时遇到的场景))

[1.3 重量级锁 vs 轻量级锁 (遇到某一种场景后的解决方案)](#1.3 重量级锁 vs 轻量级锁 (遇到某一种场景后的解决方案))

[1.4 挂起等待锁 vs 自旋锁 (解决方案的典型实现)](#1.4 挂起等待锁 vs 自旋锁 (解决方案的典型实现))

[1.5 普通互斥锁 vs 读写锁](#1.5 普通互斥锁 vs 读写锁)

[1.6 可重入锁 vs 不可重入锁](#1.6 可重入锁 vs 不可重入锁)

[1.7 公平锁 vs 非公平锁](#1.7 公平锁 vs 非公平锁)

[二. synchronized的详细介绍](#二. synchronized的详细介绍)

[2.1 锁升级](#2.1 锁升级)

[2.2 锁消除](#2.2 锁消除)

[2.3 锁粗化](#2.3 锁粗化)

[三. 总结](#三. 总结)


一. 锁策略

1.1 什么是锁策略

锁在加锁的时候, 会有哪些特征和行为.

1.2 悲观锁 vs 乐观锁 (加锁时遇到的场景)

悲观锁: 加锁的时候, 预测接下来的锁竞争会非常激烈, 就需要针对这种情况做一些额外的工作.

乐观锁: 加锁的时候, 预测接下来的锁竞争不激烈, 就不需要做额外的工作.

注: 悲观和乐观不是特指某一种锁, 而是指锁具有这样的特性.

1.3 重量级锁 vs 轻量级锁 (遇到某一种场景后的解决方案)

重量级锁: 在悲观 的场景下, 需要付出更多的代价. => 更低效

轻量级锁: 在乐观 的场景下, 付出更少的代价. => 更高效

1.4 挂起等待锁 vs 自旋锁 (解决方案的典型实现)

挂起等待锁 : 操作系统内核级别的, 当前线程遇到锁竞争之后阻塞(不消耗cpu资源), 等待操作系统内核来唤醒. (锁竞争激烈, 一个线程阻塞后不知道什么时候能获取锁, 就挂起等待, 此时, 不消耗资源)

自旋锁: 应用程序级别的, 当前线程遇到锁竞争之后忙等(while...)(疯狂消耗cpu资源), 等待竞争结束.

(锁竞争不激烈, 一个线程阻塞后(没有真的阻塞, 而是忙等), 很快就可以获取锁, 就忙等)

悲观锁 => 重量级锁 => 挂起等待锁

乐观锁 => 轻量级锁 => 自旋锁

1.5 普通互斥锁 vs 读写锁

synchronized是普通互斥锁: 加锁 解锁

读写锁: 读与读不互斥, 读与写互斥, 写与写互斥 因为读是线程安全的, 写是线程不安全的.(读多写少的场景)

1.6 可重入锁 vs 不可重入锁

synchronized是可重入锁.

ReentrantLock默认状态下是不可重入锁, 可以设置为可重入锁.

面试题: 如何实现一个可重入锁? (重要)

加锁时: 第一次加锁时, 记录当前是哪个线程进行加锁. 之后每次进行加锁时, 判断是否是第一次记录时的线程加锁.并且原子类count进行自增+1操作.

解锁时: 原子类count进行自减-1操作, 减到0时, 第一次记录的线程释放锁.

1.7 公平锁 vs 非公平锁

公平锁: 线程获取锁讲究先来后到.

非公平锁: 线程获取锁不要求先来后到.

synchronized是非公平锁.

ReentrantLock 默认是非公平锁, 可以设置为公平锁.


二. synchronized的详细介绍

2.1 锁升级

无锁 => 偏向锁 => 轻量级自旋锁 => 重量级挂起等待锁

偏向锁: 不是真的锁, 而是标记.

拿到偏向锁(没有真的加锁, 只是标记)的线程在运行的过程中, 遇到了其他的线程竞争这个锁, 拿到偏向锁的线程就会抢先一步真加锁.

2.2 锁消除

jvm 判断当前代码逻辑是否需要加锁, 若不需要, jvm就会优化代码(锁消除).

2.3 锁粗化

把一些连续的.细粒度的加锁优化成一次粗粒度的加锁.


三. 总结

  1. 悲观锁, 乐观锁(不是某一种具体的锁, 而是锁具有这样的特性) (加锁时遇到的场景)

  2. 重量级锁, 轻量级锁(遇到某一种场景时的解决方案)

  3. 挂起等待锁(阻塞), 自旋锁(忙等)(解决方案的典型实现)

  4. 悲观锁 => 重量级锁 => 挂起等待锁

乐观锁 => 轻量级锁 => 自旋锁

  1. 普通互斥锁, 读写锁

  2. 可重入锁, 不可重入锁 (可重入锁的实现)

7, 公平锁, 非公平锁

8, synchronized是自适应的, 普通互斥锁, 可重入锁, 非公平锁

9, 锁升级(无锁 -> 偏向锁 -> 轻量级自旋锁 -> 重量级挂起等待锁)

10, 锁优化

11, 锁粗化(将连续的, 细粒度的加锁优化成为一次粗粒度加锁)

相关推荐
LabVIEW开发1 分钟前
LabVIEW 连接板:28 个端子怎么排,优先级怎么定
java·算法·labview
天天被压力33 分钟前
【A股分钟级高频数据完全手册 #07】北交所历史分钟K线接口:京市Pro版分时批量
java·人工智能·python
天天被压力39 分钟前
【A股分钟级高频数据完全手册 #08】股票日、分时数据接口对比:普通分时与Pro版差异实测
java·人工智能·python
特立独行的猫A1 小时前
AI 时代,我为什么推荐用 cj-tauri 开发桌面应用
java·后端·python
金銀銅鐵1 小时前
从一个类名到一张类图:用反射自动生成 PlantUML
java·后端·uml
疯华整猫1 小时前
被杀掉之后:我把 Android 的「唤起 + 常驻」重做了一遍
前端·面试·架构
nice_lcj5201 小时前
Java 并发容器入门:ConcurrentHashMap、CopyOnWriteArrayList、阻塞队列
java·面试·并发编程·阻塞队列·concurrenthashmap·copyonwritearraylist
微小的鱼2 小时前
Linux的渲染与显示系统链路
android·java·linux
Hhy_11072 小时前
《C++深度解构06》手撕 string —— 从底层内存管理到深浅拷贝彻底吃透
c语言·开发语言·c++·学习·visual studio
starzy19902 小时前
深入理解Scala函数定义:从方法到函数的类型跨越
开发语言·scala