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. 循环等待, 多个线程构成了一个循环链。
相关推荐
落魄实习生16 分钟前
Agent Scope Java 2.x 系列【7】工具使用
java·开发语言·ai
旺仔学长 哈哈23 分钟前
springboot钓鱼爱好者交流平台APP设计与实现
java·spring boot·mysql·充电桩管理系统
茉莉玫瑰花茶1 小时前
GO [ 方法 ]
开发语言·后端·golang
狗凯之家源码网1 小时前
微博图床 PHP 系统搭建与实战应用指南
android·开发语言·php
自强的小白2 小时前
核心功能(Service接口)
java·mybatis
乌暮3 小时前
深入理解 Java 泛型:把「万能盒子」用对、用稳
java·开发语言·后端·学习
大猫和小黄3 小时前
深入理解 Java Optional:从设计哲学到工程实战
java
数据库百宝箱3 小时前
rum&gin索引对比
java·数据库·gin
2601_962218613 小时前
C语言中三种库的编译和使用方法
开发语言·c++