锁策略和死锁问题

锁策略

  • 乐观锁 vs 悲观锁
  • 重量级锁 vs 轻量级锁
  • 自旋锁 vs 挂起等待锁
  • 读写锁 vs 互斥锁
  • 公平锁 vs 非公平锁
  • 可重入锁 vs 不可重入锁
  • 死锁
    • 死锁产生的必要条件
    • 如何简单的解决死锁问题
  • 小结

这里不是描述的某个特定锁,而是描述的锁的特性,描述的是"一类锁".

乐观锁 vs 悲观锁

乐观锁: 预测在该场景中,不太会出现锁冲突的情况.
悲观锁: 预测在该场景中,非常容易出现锁冲突.
锁冲突: 两个线程尝试获取同一把锁,一个线程能获取成功,另一个线程阻塞等待.

重量级锁 vs 轻量级锁

重量级锁: 加锁的开销比较大(花的时间多,占用系统资源多), 大多是悲观锁.
轻量级锁: 加锁的开销比较小(花的时间少,占用系统资源少), 大多是乐观锁.

自旋锁 vs 挂起等待锁

自旋锁: 是轻量级锁的一种典型实现,在用户态下,通过自旋的方式(while循环), 实现加锁效果的.
自旋锁会消耗一定的cpu资源,但是可以做到最快速度拿到锁.
挂起等待锁: 是重量级锁的一种典型实现, 通过内核态,借助系统提供的锁机制,当出现锁冲突的时候,
会牵引到内核对于线程的调度,使冲突的线程阻塞等待.
挂起等待锁消耗的cpu资源更少,无法保证第一时间拿到锁.

读写锁 vs 互斥锁

读写锁: 很多读数据的线程之间并不互斥,而写操作要求与任何人互斥.
1. 两个线程,一个线程读加锁,另一个线程也是读加锁,不会产生锁竞争.
2. 两个线程,一个线程读加锁,另一个线程是写加锁,会产生锁竞争.
3. 两个线程,一个线程写加锁,另一个线程也是写加锁,会产生锁竞争.
互斥锁: 锁本身是靠互斥性发挥作用的.

公平锁 vs 非公平锁

公平锁: 遵守先来后到的锁.
非公平锁: 那就是不遵守先来后到的锁.
操作系统内部的线程调度是随机的,如果不做任何额外的限制,锁就是非公平锁.
要想实现公平锁,就需要一些额外的数据结构来支持.(需要记录每个线程的阻塞等待的时间).

可重入锁 vs 不可重入锁

不可重入锁: 一个线程,针对同一把锁,连续加锁两次,产生死锁了.
可重入锁: 一个线程,针对同一把锁,连续加锁两次,没产生死锁.
public synchronized void add() {synchronized (this) {count++;}
}
// 先调用方法add(),这里假设加锁成功.
// 接下来进入代码块,再次针对this对象加锁.

我们对this对象加两次锁(如果是静态方法,是针对类对象加锁.普通方法是针对this对象加锁),此时就会产生锁竞争.(这里写的synchronized是可重入锁,并不会产生死锁,只是用它来表示锁)
为什么呢?
在代码块中,this上的锁必须要等到add方法执行完毕释放后,才能释放.可是这里的逻辑是又加了一个锁,add方法没有释放锁,第二次加锁进入阻塞等待,这里就一直等下去了,也就是产生死锁了.

如果是不可重入锁,这把锁不会保存,是哪个线程对它进行加锁,只要它处于加锁状态,
又收到了"加锁"请求,就会拒绝加锁,此时就会产生死锁.
如果是可重入锁,则是会让这把锁保存,是哪个线程对它进行加锁,就会先对比一下,
看看加锁的线程是不是持有这把锁的线程,就可以灵活判定了.
synchronized 是可重入锁.
public synchronized void add() {synchronized (this) {count++;synchronized (this) {count++;}}
}
// 只有第一个synchronized真正加锁了,后面的都只是虚晃一枪,并没有真正加锁.
// 释放锁也是在最外层的synchrinized中释放的.
// 那么我们怎么知道哪个是最后一个锁呢?
// 让锁这里有一个计数器就可以了

死锁

死锁: 多个线程同时被阻塞,它们中的一个或者全部都在等待资源释放.由于线程无限被阻塞,因此程序不可能正常终止.

  1. 一个线程, 一把锁, 是不可重入锁, 该线程连续加锁两次, 就会出现死锁.
  2. 两个线程, 两把锁, 这两个线程先分别获取到一把锁, 然后再同时尝试获取对方的锁.
public class Demo27 {private static Object locker1 = new Object();private static Object locker2 = new Object();public static void main(String[] args) {Thread thread1 = new Thread(() -> {synchronized (locker1) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (locker2) {System.out.println("thread1加入了两把锁");}}});Thread thread2 = new Thread(() -> {synchronized (locker2) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (locker1) {System.out.println("thread2加入了两把锁");}}});thread1.start();thread2.start();}
}

此时代码就会进入阻塞等待,thread1要想结束,就必须获取到locker2, thread2要想结束,就必须获取到locker1,这两个线程互相冲突,构成死锁.
在这里插入图片描述
3. N个线程M把锁
这里有一个哲学家就餐问题.
假设有5个哲学家, 5根筷子,哲学家主要做两件事,

  1. 思考人生,放下筷子.
  2. 吃面,会分别拿起左手和右手的筷子,再去夹面条吃.

基于上述模型,绝大多数情况下,这些哲学家都可以很好的工作的.但是如果出现极端情况,就会出现死锁.比如说,同一时刻,5个哲学家都想吃面,同时拿到左手的筷子,此时拿不到右手的筷子,就会进入阻塞等待,会进入死锁.

死锁产生的必要条件

只要破坏其中任意一个条件,就可以避免出现死锁.

  1. 互斥使用: 一个线程获取到一把锁后,别的线程不能获取到这个锁.(锁的基本特性)
  2. 不可抢占: 锁只能被持有者主动释放, 而不能被其它线程直接抢走.
  3. 请求和保持: 一个线程去尝试获取多把锁, 在获取多把锁的过程中, 会保持对第一把锁的获取状态.
  4. 循环等待: 相当于thread1要想结束,就必须获取到locker2, thread2要想结束,就必须获取到locker1,这种情况.

如何简单的解决死锁问题

针对锁进行编号, 并且规定加锁的顺序.约定,每个线程如果要获取多把锁, 就必须先获取编号小的锁, 后获取编号大的锁.
只要所有的线程加锁顺序,严格遵守上述情形, 就一定不会出现循环等待.
比如在哲学家就餐问题中, 给每个筷子(锁)进行编号, 按照编号从小到大获取,就不会出现循环等待.

小结

本篇博客讲述了关于锁的特性, 有不足的地方还请多多补充, 希望有收获的小伙伴多多支持.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/319.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java配置环境变量的过程

第一步:先找到你下载java的文件夹。 第二步:点击它进入看到新的文件夹继续点击。 第三步:点击bin文件。 第四步:点进去bin文件之后复制上述文件的地址。 第五步:回到你的电脑位置右键鼠标点击空白位置出现属性点进去 第…

设计模式胡咧咧之策略工厂实现导入导出

策略模式(Strategy Pattern) 定义: 定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。 本质: 分离算法,选择实现 应用场景 何时使用 一个系统有许多类,而区分他们的只是他们直接…

复合机器人在磁钢上下料中的应用及其优势分析

复合机器人是一种集成了移动机器人和工业机器人功能的设备,其独特之处在于拥有“手、脚、眼、脑”的综合能力,从而实现了更高的灵活性和操作效率。在磁钢上下料的应用场景中,复合机器人能够发挥显著的优势。 首先,复合机器人可以根…

Photomator 3.3.5 (macOS Universal) - 照片编辑软件

Photomator 3.3.5 (macOS Universal) - 照片编辑软件 适用于 Mac、iPhone 和 iPad 的终极照片编辑器 请访问原文链接:https://sysin.org/blog/photomator/,查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org Photomat…

计算机网络 -- 网络编程基础

一 学习准备 1.1 IP地址 在 前文中我们提到过: IP 是全球网络的基础,使用 IP 地址来标识公网环境下主机的唯一性,我们可以根据 目的IP地址 进行跨路由器的远端通信。 但是我们也提到了,通过 IP 地址,只能寻找到目标主机&#xff…

视频质量度量VQM算法详细介绍

视频质量评价 视频质量评价(Video Quality Assessment,VQA)是指通过主观、客观的方式对视频图像的内容、画质等,进行感知、衡量与评价。 ITU definations subjective assessment: the determination of the quality or impairment of programme-like pictures presented…

【代码随想录】【动态规划】day48:打家劫舍

打家劫舍1 def rob(self, nums):""":type nums: List[int]:rtype: int"""# 分为两个情况,偷还是不偷,# dp[i]为考虑到第i个房间时的最大值if len(nums) 0: # 如果没有房屋,返回0return 0if len(nums) 1: #…

【 书生·浦语大模型实战营】作业(五):LMDeploy 量化部署

【 书生浦语大模型实战营】作业(五):LMDeploy 量化部署 🎉AI学习星球推荐: GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系…

Linux debian gdb dump

1.开发背景 记录 debian 下应用程序崩溃调试方法 2.开发需求 程序越界可以定位到越界的位置附近 3.开发环境 debian 操作系统,如果不支持需要查看是否存在对应的可执行文件 4.实现步骤 4.1 设置 dump 输出大小 ulimit -c unlimited # 设置输出大小 生成core 文…

【QT+OpenCV】车牌号检测 学习记录 遇到的问题

【QTOpenCV】车牌号检测 学习记录 首先在QT里面配置好OpenCV .pro文件中加入: INCLUDEPATH G:/opencv/build/include LIBS -L"G:/opencv/build/x64/vc14/lib"\-lopencv_core \-lopencv_imgproc \-lopencv_highgui \-lopencv_ml \-lopencv_video \-lo.c…

Linux下SPI设备驱动实验:使用内核提供的读写SPI设备中的数据的函数

一. 简介 前面文章的学习,已经实现了 读写SPI设备中数据的功能。文章如下: Linux下SPI设备驱动实验:验证读写SPI设备中数据的函数功能-CSDN博客 本文来使用内核提供的读写SPI设备中的数据的API函数,来实现读写SPI设备中数据。 …

HTML5+JavaScript实现本地视频/音频播放器

HTML5JavaScript实现本地视频/音频播放器 HTML5 提供了本地视频和音频播放器的支持&#xff0c;通过 <video> 和 <audio> 标签&#xff0c;这些标签支持多种媒体格式&#xff0c;并且可以通过 JavaScript 进行控制&#xff0c;实现功能比较完整的本地视频音频播放器…

MySQL 8.0 新特性之 Clone Plugin

个人感觉&#xff0c;主要还是为 Group Replication 服务。在 Group Replication 中&#xff0c;如果要添加一个新的节点&#xff0c;这个节点差异数据的补齐是通过分布式恢复&#xff08; Distributed Recovery &#xff09;来实现的。 在 MySQL 8.0.17 之前&#xff0c;只支…

【数据结构】队列(链表模拟队列)

学习本章节必须具备 单链表的前置知识&#xff0c; 建议提前学习&#xff1a;点击链接学习&#xff1a;单链表各种功能函数 细节 详解 本章节是学习用 单链表模拟队列 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff…

javase基础汇总学习

目录 背景步骤宏观微观理论基础用法面向对象数据类型基础语法&#xff08;关于方法&#xff09;try&#xff08;正常的逻辑代码&#xff09;catch&#xff08;这个和异常有关系&#xff09;finally&#xff08;经典面试题&#xff09; 高阶使用序列化泛型注解反射 总结 背景 后…

大型网站系统架构演化实例_3.使用服务集群改善网站并发处理能力

1.使用服务集群改善网站并发处理能力 使用集群是网站解决高并发、海量数据问题的常用手段。当一台服务器的处理能力、存储空间不足时&#xff0c;不要企图去更换更强大的服务器&#xff0c;对大型网站而言&#xff0c;不管多么强大的服务器&#xff0c;对大型网站而言&…

Jenkins 的构建时执行时间问题

我们希望我的项目能够在特定的时间自动执行&#xff0c;我们需要设定一个定时任务。 Jenkins 的定时任务是通过 Cron 任务来实现的&#xff0c;但是由有点不一样。 H/2 * * * * 比如说上面的设置就是每 2 分钟执行一次。 希望每分钟执行一次 Jenkins 的每分钟执行一次的设置…

【AI工具之Prezo如何自动生成PPT操作步骤】

先说优缺点&#xff1a; 最大的优点就是免费&#xff08;但说实话功能和体验方面很弱&#xff09;支持中文提问&#xff08;最好用英文&#xff09;&#xff0c;智能生成图文&#xff08;但是只能生成英文内容&#xff09;可以AI生成图片&#xff0c;图片很精美酷炫&#xff0…

Eureka基础介绍和使用

目录 一.理论基础 二.父项目 2.1 新建父项目 2.2 管理依赖 三.子项目 3.1 新建子项目 3.2 注册中心Server依赖和启动类和配置文件 3.3 生产者Client 依赖和启动类和配置文件 3.5 消费者Custmer依赖和配置类、启动类和配置文件 四.心跳 五.公共资源项目 5.1新建实体…

空心电抗器的matlab建模与性能仿真分析

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 空心电抗器是一种无铁芯的电感元件&#xff0c;主要由一圈或多圈导线绕制在非磁性材料制成的空心圆筒或其他形状的骨架上构成。其工作原理基于法拉第电磁感应定律&#xff0c;…