我的创作纪念日——多线程进阶分享

多线程-进阶

1. 锁的策略

1.1 乐观锁&悲观锁

  1. 乐观锁

    • 预计在线程中数据大概率不会被其他线程拿去修改

    • 对于加锁所作的准备较少。只有当修改的操作真正发生了,才会进行加锁操作

    所以乐观锁适用于多读少写的情况,可以降低加锁频率,提升效率。

  2. 悲观锁

    • 预计在线程中数据大概率会被其他线程拿走做修改操作
    • 加锁前的准备工作比较多

    所以悲观锁适用于对于线程安全要求高的场景。

1.2 轻量级锁&重量级锁

  1. 轻量级锁

    • 对应于乐观锁
    • 加锁前的操作占用的资源少,造成的阻塞情况少
    • 较少进行内核态和用户态的切换
    • 较少进程之间的调度
  2. 重量级锁

    • 对应于悲观锁
    • 加锁前的准备工作多,容易造成线程阻塞
    • 大量内核态和用户态的切换
    • 易引发进程之间的调度

    乐观和悲观是对于未加锁结果的一种猜想

    重量轻量是对于加锁后资源消耗的一种评价

    从这个角度说,这两组概念都是在描述加锁的工作对于资源的消耗。乐观就是消耗的资源较少,悲观反之。

1.3 自旋锁&挂起等待锁

  1. 自旋锁

    • 重复、快速地进行锁的获取(称为自旋“

    • 会增大cpu的消耗,可能会造成“忙等”

    • 适用于乐观、轻量的策略(虽然一直不停地在获取锁,但是过不了多久就能够真正获取到锁)

    • 伪代码:

      while(抢锁失败) {
          加锁...
      }
      

    优点:

    1. 在锁竞争平缓的情况下能够降低资源消耗,加快运行速度,避免线程之间因为简单的任务而阻塞。

    2. 其他线程一旦把锁释放,就会第一时间拿到锁

    缺点:

    1. 如果遇到锁竞争激烈的情况,会有其他线程竞争不到锁的情况。
    2. 竞争不到锁,但是还会一直进行获取锁,造成cpu的资源浪费
  2. 挂起等待锁

    • 遇到锁竞争的情况就挂起等待

    • 适用于锁竞争激烈的情况

    • 与悲观、重量相对应

    • 伪代码:

      while(抢锁失败) {
          wait();
      }
      

    优点:

    避免了cpu资源浪费

    缺点:
    不能第一时间抢到锁,什么时候能加锁,由系统决定

1.4 普通互斥锁&读写锁

  1. 普通互斥锁

    • 类似于synchronized,在一个线程对于同一个对象进行加锁的时候另一个线程不能对于这个对象的锁进行获取
  2. 读写锁

    • 读锁

      • 给读操作加锁,读的过程中其他线程只能再读,不能写

      读的操作并没有线程安全问题,但是只局限于读,如果读的过程中,把正在读取的值拿走进行修改,那么就会产生读到“脏值”的情况。

    • 写锁

      • 给写操作加锁,在一个线程写的时候其他线程不能读,也不能写

      写就是修改,修改就会有线程安全问题,如果在修改的过程中读就可能会读到“脏值”,如果在修改的过程中继续修改就可能会引起数据的混乱。

1.5 公平锁&非公平锁

  1. 公平锁

    • 基于前人发明的、前人规定的规则,“先来后到”就是公平
    • “先来后到”:一个线程拥有锁的时间越长,那就越应该下一个获取到锁
    • 有效避免了线程饿死
  2. 非公平锁

    • 在释放锁之后,随机等概率竞争锁的情况
    • mutex锁就是非公平锁,synchronized是封装mutex的锁,故而也是非公平锁

    这里的“公平”和“非公平”只是基于前人发明的角度上,其实,在“等概率竞争锁”的情况下也是一种“公平“。

1.6 可重入锁&不可重入锁

  1. 可重入锁

    • 可以重复加锁

    • synchronized就是可重入锁

    • 伪代码:

      lock();// 第一次加锁之后继续加锁
      lock();// 第二次加锁>
      
  2. 不可重入锁

    • 不可重复加锁
    • c++中的mutex就是不可重入锁
    • 不可重入锁在进行重复加锁的时候会出现死锁现象

结论:

  1. 乐观锁-轻量级锁-自旋锁都是对应的

  2. 悲观锁-重量级锁-挂起等待锁是对应的

  3. 乐观:认为自己的家不会被偷,那就在家被偷或者被贼盯上的时候再去给门上锁

    悲观:认为自己的家已经被贼盯上了,一直上着锁

  4. 轻量级锁:只给家门上一个容易打开的锁,开锁的时候消耗自己的时间精力也会较少,乐观地认为贼不会偷有锁的家

    重量级锁:给家门上一个不容易打开的防盗锁,,开锁的时候消耗自己的时间精力会增加,悲观地认为一直有贼盯上我的房子

  5. 自旋锁: 乐观地认为没有多少贼盯上了自己的家,所以每天都去看看自己的家有没有被偷,优点是家一被偷就能够知道,就能立马上锁,缺点是费时费力

    挂起等待锁:悲观地认为有很多贼已经盯上了自己的家,所以上一把不容易打开的锁,当有人敲门的时候再去检查是谁来,如果是贼那就不开门,让锁挂起等待,自己继续在家里玩游戏。好处是减少了自己的任务量,可以有效防止多个贼同时顶上自己家的情况,缺点是这把锁自己也不容易打开

  6. 普通互斥锁:

2. CAS

乐观锁的常用实现算法是CAS算法,全称是CompareAndSwap(比较和交换),这个也是cpu中存在的一条cas指令。

伪代码:

boolen cas(address, expectedValue, swapValue) {
    if (&address == expectedValue) {
        &address = swapValue;
        return true;
    }
    return false;
}

address表示内存,expectedValue和swapValue是两个寄存器。

如果内存中的值与交换前所期望的值相等,那就与准备交换的值进行交换(说是交换,其实就是赋值)。

expectedValue就是内存中值的”旧值“,通过与这个”旧值“进行比较,就能够发现此值在修改前是否进行了改动,防止读到”脏值“。


3. synchronized 原理

3.1 锁的升级

synchronized锁是一把自适应锁,当一个线程执行到synchronized的时候,如果这个线程还未加上锁,那么synchronized就会经理以下过程:

  1. 偏向锁阶段

    核心思想就是”懒汉模式”,非必要不加锁(升级成轻量级锁就是必要的时候)。

    • 在这个阶段并不会真正地加上锁,但是会对于有加锁可能性的对象在对象头进行标记,标记这个对象属于哪个线程
    • 如果后续没有线程竞争这把锁,那就不再真正的进行加锁,就省下了加锁的消耗
    • 如果一旦发生线程安全问题,立马升级为轻量级锁

    感觉有点像占着茅坑不拉屎,一旦有人来了就蹲下拉屎,没人来也就占着。(学校的占座不就是这样吗🐶)

  2. 轻量级锁阶段

    • 随着线程之间少量的锁竞争,偏向锁状态被消除(并不是解锁了),进入轻量级锁阶段,这个阶段由自旋锁进行实现

    • synchronized内部会统计当前这个锁对象有多少个线程想要竞争,如果数量多,那么还会升级为重量级锁

      因为锁的竞争大的话,对于自旋锁来说大量的线程都在自旋,这样不能提高效率,反而会带来更多的cpu消耗。

  3. 重量级锁阶段

    • 随着线程之间大量的锁竞争,轻量级锁升级为重量级锁
    • 此时不会对于锁竞争发生自旋,而是进入阻塞等待状态,就会有大部分的线程让出cpu
    • 当目前占有锁的线程执行完毕以后就会释放锁,剩余线程等概率竞争锁

3.2 锁的工作原理

  1. synchronized锁是:

    1. 对于以下锁的状态自适应:
      1. 乐观、悲观锁
      2. 自旋、挂起等待锁
      3. 轻量级、重量级
    2. 不是读写锁
    3. 非公平锁
    4. 可重入锁
  2. 系统原生mutex锁是:

    1. 悲观锁
    2. 重量级锁
    3. 挂起等待锁
    4. 互斥锁
    5. 非公平锁
    6. 不可重入锁

    4. 其他的优化操作

    4.1 锁消除

    当编译器发现加锁的这一部分代码中,并未涉及变量修改的部分,那么就会自动将锁去掉。

    使用线程安全的StringBuffer举个例子:

    StringBuffer sb = new StringBuffer();
    sb.append("a");
    sb.append("b");
    sb.append("c");
    sb.append("d");
    

    这段代码中虽然每个append 都有加锁解锁的操作,但是jvm+编译器都发现这段代码并没有真正的线程安全问题,所以就不会进行加锁和解锁,避免了资源的无谓消耗。

    4.2 锁粗化

    与锁粗化关系密切的一个重要概念是锁的粒度。

    锁的粒度就像吃的牛肉粒一样,每次加一个锁就是一个牛肉粒,有两种策略吃:

    1. 每次剥开一个牛肉粒就吃一个
    2. 每次剥开不吃,等到攒成一个大牛肉粒再吃

    两种伪代码分别对应这两种情况:

    for() {
        synchronized(locker) {
        	// TODO
        }
    }
    

    将锁粗化:

    synchronized(locker) {
        for() {
        	// TODO
        }
    }
    

4. 死锁

4.1 死锁的成因有4个:

  1. 循环等待

    当锁A唤醒需要锁B先释放,锁B唤醒需要锁A先释放,就构成了循环等待。

  2. 请求和保持

    当一个线程获取新锁的同时,它会继续对于当前已有的锁进行占有。

  3. 互斥使用

    资源被一个线程占有时,其他的线程不能同时使用。

  4. 不可抢占

    资源被一个线程占有时,其他线程不能抢占使用,只能等待当前占有者主动释放。


其中,3和4是锁的特性无法改变,但是1和2可以通过代码结构进行破坏。

比较著名的是“哲学家就餐问题”:
在这里插入图片描述

当这5名哲学家都需要吃饭的时候,餐桌上拥有的筷子数量肯定是不够用的,但是如果给哲学家加上拿筷子的顺序,那么就只会有一名哲学家在“阻塞等待”。

比如:规定每名哲学家只能先拿起编号小的筷子,那么就是0号老铁先吃
在这里插入图片描述

1号老铁进行阻塞等待,等到0号老铁吃完以后再先拿起编号小的1号筷子+2号筷子吃

在这里插入图片描述

2,3,4老铁同理。

4.2 破坏死锁

就是调整代码结构,破除循环等待这个条件。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

车载测试:如何用CANape进行ADAS实车功能测试?

前言 CANape是一款用于ECU测量、标定、诊断以及ADAS传感器数据采集的工具型软件。 测量——通过CANape不仅能采集记录ECU内部信号,还支持与车辆上的各种传感器的总线进行通信。与ECU不同,ADAS传感器不提供车辆实际运行信号,而是提供车辆运行…

3亿人民币!欧洲高性能计算联合企业从德国开始建设量子生态

(图片来源:网络) 欧洲高性能计算联合企业(EuroHPC JU)已启动招标程序,准备在德国部署一台新型Euro-Q-Exa量子计算机。 Euro-Q-Exa系统将是一台基于超导量子比特和最先进的技术研发的量子计算机&#xff0…

细粒度视觉分类的注意内核编码网络

Attentional Kernel Encoding Networks for Fine-Grained Visual Categorization 1、介绍2、方法2.1 卷积模块2.2 级联注意力模块2.3 内核编码模块2.4 整体 3、结论 在本文中,我们提出了一种用于细粒度视觉分类的注意核编码网络(AKEN)。具体来说,AKEN聚合…

RK3588+MCU机器人控制器解决方案

1 产品简介 XMP04A 是一款信迈科技基于 RK3588 设计的高性能、低功耗的边缘计算设备, 内置 NPU 算力可达 6.0TOPSINT8,以及具备强大的视频编解码能力,最高可支持 32 路 1080P30fps 解码和 16 路 1080P30fps 编码 ,支持 4K12…

浙政钉SDK安装

专有订单SDK&#xff08;jar包&#xff09;下载 专有钉钉门户 (dg-work.cn) Maven依赖 浙政钉 <!-- 浙政钉 --> <dependency><groupId>com.oracel</groupId><artifactId>zwdd-sdk-java</artifactId><version>1.2.0</version…

【推荐系统】推荐算法数学基础

【大家好&#xff0c;我是爱干饭的猿&#xff0c;本文重点介绍推荐系统涉及的数学知识、推荐系统涉及的概率统计知识。 后续会继续分享其他重要知识点总结&#xff0c;如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下吧】 上一篇文章&#xff1a;《【推…

2008. 出租车的最大盈利(动态规划)

按照 end 对每一个乘客进行排序对于每一个乘客&#xff0c;如果接他就要寻找之前小于 start 的 end 中最大的那个来计算接他的收益&#xff0c;而不接的话就是上一个乘客的收益&#xff0c;取最大值即可 class Solution:def maxTaxiEarnings(self, n: int, rides: List[List[i…

flask web开发学习之初识flask(三)

文章目录 一、flask扩展二、项目配置1. 直接配置2. 使用配置文件3. 使用环境变量4. 实例文件夹 三、flask命令四、模版和静态文件五、flask和mvc架构 一、flask扩展 flask扩展是指那些为Flask框架提供额外功能和特性的库。这些扩展通常遵循Flask的设计原则&#xff0c;易于集成…

《opencv实用探索·十五》inRange二值化图像

opencv接口如下&#xff1a; void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst);函数实现二值化功能&#xff0c;主要是将在两个阈值内的像素值设置为白色&#xff08;255&#xff09;&#xff0c;而不在阈值区间内的像素值设置为黑色&am…

C语言数组(下)

我希望各位可以在思考之后去看本期练习&#xff0c;并且在观看之后独立编写一遍&#xff0c;以加深理解&#xff0c;巩固知识点。 练习一&#xff1a;编写代码&#xff0c;演⽰多个字符从两端移动&#xff0c;向中间汇聚 我们依旧先上代码 //编写代码&#xff0c;演⽰多个字…

c++详解栈

一.什么是栈 堆栈又名栈&#xff08;stack&#xff09;&#xff0c;它是一种运算受限的数据结构&#xff08;线性表&#xff09;&#xff0c;只不过他和数组不同&#xff0c;数组我们可以想象成一个装巧克力的盒子&#xff0c;你想拿一块巧克力&#xff0c;不需要改变其他巧克…

图片和文字如何生成一个二维码?图文生成二维码的做法

图片和文字如何生成一个二维码&#xff1f;扫码查看图片和文字相信大家在日常生活中都遇到过&#xff0c;比如在扫码阅读文章的时候&#xff0c;就可以看到文章内容和配图&#xff0c;可以复制文字或者下载图片。想要将文字和图片制作成一个二维码&#xff0c;可以使用二维码生…

判断css文字发生了截断,增加悬浮提示

示例&#xff1a; 固定显示宽度&#xff0c;溢出显示...&#xff0c;利用了css的属性&#xff0c;想要实现成下面这样&#xff1a; 针对溢出的文字&#xff0c;hover显示全部。 提示很好加&#xff0c;使用tooltip组件就行了&#xff0c;难点是如何判断是否发生了文字溢出。…

android项目实战之使用框架 集成多图片、视频的上传

效果图 实现方式&#xff0c;本功能使用PictureSelector 第三方库 。作者项目地址&#xff1a;https://github.com/LuckSiege/PictureSelector 1. builder.gradle 增加 implementation io.github.lucksiege:pictureselector:v3.11.1implementation com.tbruyelle.rxpermissio…

Rusty Tuesday :Rust 基金会一行来访 Databend Labs,共话技术创新!

在当今快速发展的技术浪潮中&#xff0c;Rust 作为一种新兴的编程语言&#xff0c;凭借其卓越的内存安全特性和高效的性能&#xff0c;吸引了全球开发者的广泛关注。2023 年 12 月 05 日&#xff0c;由 Databend Labs 主办的首届 Rusty Tuesday 活动正式在北京揭开序幕。 在本…

关于微信/支付宝等平台验签/签名sign生成算法

引言 我们在日常工作中经常会遇到对接微信平台、支付宝平台、或者自己对外开放一个api服务&#xff0c;那么这里经常会出现一个名字&#xff1a;sgin&#xff08;签名&#xff09;。 举个栗子 这是微信支付统一下单接口文档&#xff0c;最简单的理解就是&#xff0c;服务端为…

52 代码审计-PHP项目类RCE及文件包含下载删除

目录 漏洞关键字:演示案例:xhcms-无框架-文件包含跨站-搜索或应用-includeearmusic-无框架-文件下载-搜索或应用功能-down等zzzcms-无框架-文件删除RCE-搜索或应用-unlink、eval 漏洞关键字: SQL注入&#xff1a; select insert update mysql_query mysql等 文件上传&#xff…

全自动网印机配件滚珠螺杆起什么作用?

全自动网印机配件主要包括印刷网板、墨水或油墨箱、墨水或油墨管道、传动部件、移动部件、传动系统、控制系统、安全保护装置等等这些。 滚珠螺杆是一种精密的传动元件&#xff0c;能够将电机的旋转运动转化为线性运动&#xff0c;从而驱动印刷机的工作台进行精确的移动&#x…

正则表达式详细讲解

目录 一、正则表达式概念 二、八元素 1、普通字符&#xff1a; 2、元字符&#xff1a; 3、通配符 .&#xff1a; 4、字符类 []&#xff1a; 5、量词&#xff1a; 6、锚点 ^ 和 $&#xff1a; 7、捕获组 ()&#xff1a; 8、转义字符 \&#xff1a; 三、日常使用的正则…

【USRP】5G / 6G OAI 系统 5g / 6G OAI system

面向5G/6G科研应用 USRP专门用于5G/6G产品的原型开发与验证。该系统可以在实验室搭建一个真实的5G 网络&#xff0c;基于开源的代码&#xff0c;专为科研用户设计。 软件无线电架构&#xff0c;构建真实5G移动通信系统 X410 采用了目前流行的异构式系统&#xff0c;融合了FP…
最新文章