沉梦听雨的编程指南 沉梦听雨的编程指南
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)

沉梦听雨

时间是最好的浸渍剂,而沉淀是最好的提纯器🚀
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)
  • 基础篇

  • 集合篇

  • 并发篇

    • Java并发基础小结
    • 锁详解
      • 死锁问题
        • 什么是线程死锁?
        • 死锁产生的原因
        • 死锁产生的条件
        • 如何预防死锁?
        • 如何避免死锁?
      • 乐观锁和悲观锁
        • 什么是乐观锁?
        • 什么是悲观锁?
        • 如何实现乐观锁?
        • 版本控制
        • CAS 算法
        • 如何实现悲观锁?
      • 学习参考
    • Synchronized和Volatile的使用与区别
    • 线程池详解
    • CompletableFuture学习
    • LocalThread学习
    • Java内存管理总结
  • JVM

  • 新特性

  • Java核心技术卷I

  • Java
  • 并发篇
沉梦听雨
2023-06-14
目录

锁详解

# 锁详解

# 死锁问题

# 什么是线程死锁?

线程死锁是指:两个或多个线程互相持有对方所需要的资源而互相等待的状态,导致程序无法继续执行下去,进而陷入死循环,无法完成任务。

# 死锁产生的原因

通常情况下,线程死锁产生的原因是: 两个或多个线程对资源的竞争和不当的资源分配。

# 死锁产生的条件

线程死锁的产生通常需要同时满足以下四个条件:

  1. 互斥条件:该资源任意一个时刻只由一个线程占用。
  2. 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:线程已获得的资源在未使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
  4. 循环等待条件: 若干线程之间形成一种头尾相接的循环等待资源关系。

# 如何预防死锁?

预防死锁只要破坏死锁产生的必要条件即可:

  1. 破坏请求与保持条件:一次性申请所有的资源。
  2. 破坏不剥夺条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
  3. 破坏循环等待条件:靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。

# 如何避免死锁?

避免死锁就是在资源分配时,借助于算法(比如银行家算法)对资源分配进行计算评估,使其进入安全状态。

# 乐观锁和悲观锁

# 什么是乐观锁?

乐观锁总是假设最好的情况,认为共享资源每次被访问的时候不会出现问题,线程可以不停地执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的资源是否被其它线程修改了。

优点

不会造成线程阻塞

缺点

在并发更新的情况下,可能会出现 ABA 问题,需要使用版本号或时间戳等机制来解决。

ABA 问题是: 在使用 CAS 算法时可能出现的一个问题。

它的本质是: 由于线程之间的竞争,导致共享数据的值在某个时间点被修改为 A,然后又被修改为 B,最后再被修改回 A,

这时候使用 CAS 算法时,比较的是共享数据的值是否等于 A,如果等于 A,则执行操作,但实际上共享数据的值已经被修改过了。

简单来说,就是在使用 CAS 算法的时候发生了误判。

典型代表

比如:使用版本号机制、CAS 算法

# 什么是悲观锁?

悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放。也就是说,共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程。

优点

安全,能够保证数据操作的正确性和一致性。

缺点

悲观锁的缺点是在高并发的情况下,会造成大量的线程阻塞,降低系统的性能。

典型代表

比如:Java 中 的 synchronized 和 ReentrantLock 等独占锁,数据库中的行级锁和表级锁。

# 如何实现乐观锁?

# 版本控制

在操作共享资源之前,先读取数据的版本号,然后将操作结果与当前版本号进行比较,如果版本号一致,则可以进行操作,如果版本号不一致,则说明数据已被其他线程修改,需要回滚并重试。

# CAS 算法

CAS 的全称是 Compare And Swap(比较与交换),用于实现乐观锁,被广泛应用于各大框架中。

CAS 的思想很简单,就是用一个预期值和要更新的变量值进行比较,两值相等才会进行更新。

是一个原子操作,底层依赖于一条 CPU 的原子指令。

原子操作 即最小不可拆分的操作,也就是说操作一旦开始,就不能被打断,直到操作完成。

# 如何实现悲观锁?

悲观锁的实现方式主要有两种:基于数据库的悲观锁和基于代码的悲观锁。

  1. 基于数据库的悲观锁

    基于数据库的悲观锁是通过数据库的锁机制来实现的。在数据库中,可以通过 SELECT ... FOR UPDATE 语句或 SELECT ... FOR SHARE 语句来获取悲观锁。

    • 当一个事务执行 SELECT ... FOR UPDATE 语句时,数据库会将所选的行加上排他锁,其他事务不能修改这些行;
    • 当一个事务执行 SELECT ... FOR SHARE 语句时,数据库会将所选的行加上共享锁,其他事务只能读取这些行,不能修改。在使用完锁后,需要及时释放锁,避免长时间占用数据库资源。
  2. 基于代码的悲观锁

    基于代码的悲观锁是通过程序代码来实现的。在 Java 中,可以使用 synchronized 关键字或 Lock 接口来实现悲观锁。

    • 使用 synchronized 关键字时,需要在方法或代码块上加锁,以确保同一时间只有一个线程可以执行这段代码;
    • 使用 Lock 接口时,需要先获取锁(调用 lock() 方法),然后执行操作,最后释放锁(调用 unlock() 方法),以确保同一时间只有一个线程可以操作共享资源。

# 学习参考

  • Java并发常见面试题总结(中) | JavaGuide(Java面试 + 学习指南) (opens new window)

  • JUC包下各种锁使用详解 | Shark Chili (opens new window)

上次更新: 2024/9/25 11:16:13
Java并发基础小结
Synchronized和Volatile的使用与区别

← Java并发基础小结 Synchronized和Volatile的使用与区别→

Theme by Vdoing | Copyright © 2023-2025 沉梦听雨 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式