Java常见技术分享-13-多线程安全-锁机制-底层核心实现机制

我觉得吧, 没必要因为不懂而感到羞耻, 不懂就去学呗 一天学不会就再来一天喽, 总有一天会明白的,所以大胆的承认自己的无知吧, 然后去追寻答案

锁的基础核心实现(两大核心)
CAS(compare and swap)

首先记住CAS 是 乐观锁 (乐观策略) 的核心实现。

阻塞与唤醒

这是悲观锁 (悲观策略)的核心实现。

上一篇章我们学习了锁的分类, 要知道所有分类的锁 , 底层最终只依赖这两种核心的实现手段, 这是根基, 不管什么维度的锁, 本质上都是这两种手段的单独使用或组合使用, 掌握它能一通百通。 也是面试的核心。 这一篇章, 我们就只聚焦这两个核心他们的以下三个知识点

  • 熟悉核心流程
  • 优缺点
  • 存在的核心问题以及解决方案

CAS

核心流程

1 . 首先核心3参数, 内存地址V, 预期旧值 A, 目标新值 B。

  1. 线程读取内存地址V 存储的 当前值 是否与 预期旧值 A 一致, 如果一致 , 则用 CAS原子命令 将 内存地址V存储的值 更新 为目标新值, 返回成功 。

  2. 不一致 ,则更新失败, 直接失败 或者 自旋重试(业务侧更新预期旧值 以及 重新计算 目标新值B 再重新尝试CAS流程)

优点

无上下文切换开销, 当并发冲突少时, 性能极高。

基于CPU原子指令 实现, 无需依赖OS 即 操作系统, 属于用户态的操作, 响应快。

缺点

当并发冲突高时, 自旋会持续占用CPU资源, 导致CPU飙升。

仅能保证单个变量操作的原子性, 多个变量就没法支持了。

核心问题 + 解决方案
  • 问题1 : ABA问题(内存地址V存的值从1 -》 2 -》 1 , 对于执行CAS操作 预期旧值是1 的线程, 误判为没变)
  • 解决方案 : 版本号机制, 比对值+ 版本号
  • 问题2 : 高竞争下自旋浪费CPU
  • 解决方案 : 自适应自旋 , 就是 通过一些指标判断当前环境竞争大与否, 如果大 , 同一时间的自旋次数少, 反之, 自旋次数多。
  • 问题3: 单变量原子性局限
  • 解决方案: 结合锁(如 synchronized ) , 拆分业务逻辑, 或把 多个变量封装成一个对象 使用AtomicReference.

阻塞唤醒

核心流程
  1. 线程竞争失败
  2. 放弃CPU执行权, 进入阻塞状态(waiting / timed_waiting),移出CPU调度队列
  3. 持有锁 线程 释放锁时, 唤醒阻塞队列中 等待线程
  4. 被唤醒的线程 重新进入 就绪队列
  5. 等待CPU调度后 再次竞争锁
优点

并发冲突高时, 线程由于直接阻塞, 所以就不会占用CPU资源, 也就不会浪费CPU资源。

支持多变量, 复杂逻辑的线程安全, 使用场景更广。

缺点

线程阻塞 / 唤醒 , 涉及 用户态 -》 内核态(OS) -》 用户态 切换,主要是在这过程中上下文切换开销大。 且线程被唤醒后,存在CPU调度的延迟, 响应不如 CAS。

核心问题 + 解决方案
  • 问题1 : 阻塞唤醒开销大
  • 解决方案: 前置CAS 优化, 比如synchronized 先 自旋CAS , 失败再则色, 来减少阻塞的概率。
  • 问题2 : 线程唤醒后 ,竞争锁 ,仍可能失败(惊群效应)
  • 解决方案 : 这种有两种方案 一种用公平锁, 确保拿锁线程的顺序, 另一种方案 则是 重试一定次数之后, 直接失败处理, 不重试了。
  • 问题3 : 死锁风险
  • 解决方案: 避免锁的循环依赖, 按照固定顺序 加锁, 设置锁超时。
补充一下-死锁的四个必要的条件
  1. 一个锁只能被一个线程占用
  2. 请求与保持, 请求新的锁, 保持对已有的锁的占用
  3. 不可剥夺, 线程占用的锁不能被强行剥夺。
  4. 循环等待, 多个线程构成了一个循环链。
相关推荐
开源之眼2 小时前
《github star 加星 Taimili.com 艾米莉 》为什么Java里面,Service 层不直接返回 Result 对象?
java·后端·github
Maori3163 小时前
放弃 SDKMAN!在 Garuda Linux + Fish 环境下的优雅 Java 管理指南
java
用户908324602733 小时前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
小王和八蛋4 小时前
DecimalFormat 与 BigDecimal
java·后端
beata4 小时前
Java基础-16:Java内置锁的四种状态及其转换机制详解-从无锁到重量级锁的进化与优化指南
java·后端
IT探险家4 小时前
你的第一个 Java 程序就翻车?HelloWorld 的 8 个隐藏陷阱
java
随风飘的云4 小时前
SpringBoot 的自动配置原理
java
SimonKing4 小时前
觅得又一款轻量级数据库管理工具:GoNavi
java·后端·程序员
Seven975 小时前
BIO详解:解锁阻塞IO的使用方式
java
oak隔壁找我15 小时前
JVM常用调优参数
java·后端