多线程(进阶一:锁策略)

news2024/10/7 2:26:44

一、乐观锁和悲观锁

二、轻量级锁和重量级锁

三、自旋锁和挂起等待锁

四、普通互斥锁和读写锁

五、公平锁和非公平锁

六、可重入锁和不可重入锁

七、synchronized和Linux的mutex锁的简单比较

八、synchronized的自适应

一、乐观锁和悲观锁

乐观锁:在加锁之前,预估锁冲突的概率比较小,因此加锁的时候就不会为此做太多的准备,加锁做的事情比较少,因此加锁的速度也就可能更快。

悲观锁:在加锁之前,预估锁冲突的概率比较大,因此加锁的时候就会做大量的准备,加锁做的事情比较多,因此加锁的速度也就可能更慢。


二、轻量级锁和重量级锁

轻量级锁:运行代码之后,锁冲突的概率比较小,因此加锁的开销比较小,速度也比较快。

重量级锁:运行代码之后,锁冲突的概率比较大,因此加锁的开销比较大,速度也比较慢。

注意:这里和乐观、悲观锁不同的是,乐观、悲观锁是加锁之前进行的预估,而这里指的是加锁之后对结果的评价。


三、自旋锁和挂起等待锁

自旋锁:是轻量级锁的一种典型实现,加锁的时候,如果加锁失败,不会就此退出锁竞争,而是会循环不停的进行锁竞争,这次锁竞争失败了就再次进入循环竞争锁,直到加锁成功,才退出循环。

这种反复快速的执行,就称为 “自旋”,同时,自旋锁也是乐观锁,只要其他线程释放了锁,它就能第一时间加锁成功,这样它的加锁速度也很快,但如果有很多线程要加锁,也没必要使用自旋锁了,会白白浪费cpu资源。

等待挂起锁:是重量级锁的一种典型体现,也是悲观锁,加锁的时候,如果加锁失败,就会等待一段时间,这段时间它不会去进行加锁,和别的线程锁竞争,这时候就能把一些cpu资源让出来了,用这些cpu资源可以干一些其他事情,等一段时间过后,会再次尝试加锁,如果失败还是重复以上工作,成功就拿到锁了,没啥好说的。

当等待挂起的时候,会有内核调度器介入,这一块要完成的操作就多了,从而要获取锁的时间花费也更多一些。


四、普通互斥锁和读写锁

普通互斥锁:类似synchronized这种,操作涉及到加锁、解锁

读写锁:这里加锁的情况分为两种:加读锁,加写锁

读锁和读锁之间,不会涉及到锁冲突(不会阻塞)

写锁和写锁之间,会涉及到锁冲突(会阻塞)

读锁和写锁之间,会涉及到锁冲突(会阻塞)

当一个线程加读锁时,另一个线程只能读,不能写

当一个线程加写锁时,另一个线程不能写,也不能读

为啥要引入读写锁?

如果两个线程只读,这个操作本身就是安全的,不需要进行加锁。但是如果使用synchronized来加锁,读和读之间会涉及到锁竞争(阻塞),但我们也不能完全不给读操作加锁,就怕一个线程读,一个线程写,这时候肯定就有线程安全问题。

读写锁,就能很好的解决上述问题。

如果只有读的操作,读操作中不会有修改操作,这时候每个线程读的数据都是同一个不变的数据,如果加锁了,就会耗费一些没必要消耗的资源空间,不如加个读锁,读的时候不会锁竞争,写的时候才会,这样就能省去很多不必要的资源开销了(锁冲突的开销)


 五、公平锁和非公平锁

公平锁:如果线程和线程之间,锁竞争的时间大小不一样,按照锁竞争时间久的线程先拿到锁,有先后顺序(先来后到的意思)

非公平锁:线程和线程之间没有拿锁顺序,随机调度,各凭各的本事拿锁。

这里使用公平锁,就能很好的解决线程饿死的这一问题。而要想实现公平锁,就需要引入额外的数据结构(引入队列,记录每个线程的先后顺序),才能实现公平锁。


六、可重入锁和不可重入锁

可重入锁:如synchronized,加锁一段代码,锁里面可以再进行一次加锁,锁里面可以嵌套多个锁,里面是用计数器这种方式对加锁技术,并判断是否解锁,是可重入锁。

不可重入锁:系统自带的锁,不能连续加锁两次。


七、synchronized和Linux的mutex锁的简单比较

synchronized:乐观锁 / 悲观锁自适应

                        轻量级锁 / 重量级锁自适应

                        自旋锁 / 挂起等待所自适应

                        不是读写锁

                        非公平锁

                        可重入锁

mutex:          悲观锁

                        重量级锁

                        挂起等待所

                        不是读写锁

                        非公平锁

                        不可重入锁


八、synchronized的自适应

synchronized内部优化的很好,有自适应性,通常都可以无脑用,而且效率也不会低。

1、锁升级

(1)偏向锁阶段

核心思想:“懒汉模式”,就是能不加锁,就不加锁,能晚加锁就晚加锁;所谓的偏向锁,并不是真的加锁了,只是做了个非常轻量的标记。

一旦有线程来竞争这个锁,持有偏向锁的线程能第一时间拿到这个锁,如果没有其他线程竞争锁,下次还是拿到锁的线程大概率还是持有偏向锁的线程。总的来说,当有锁竞争的情况下,偏向锁没有提高效率,在没有锁竞争的情况下,偏向锁就能大幅度的提高效率了。

这个标记是锁里面的一个属性,每个锁都有自己的标记,当锁对象首次加锁是,没有涉及到锁竞争,这个阶段就是偏向锁阶段,一旦涉及到锁竞争,就会升级成轻量级锁阶段。

(2)轻量级锁阶段

此处的轻量级锁就是通过自旋的方式实现的,假设有锁竞争,但不多,就会处于轻量级锁阶段,它的优势:当其他线程释放锁了,处于轻量级锁阶段的线程能第一时间拿到锁;劣势:比较消耗cpu资源,因为是自旋的方式实现的,会有个循环一直尝试拿锁。

当线程多了,轻量级锁就不合适了,每个线程都循环尝试拿锁,但如果已经有线程拿到锁了,其他线程要阻塞等待,但等待的这过程是会有循环不断的尝试拿锁,这里消耗的cpu资源就很多了。这时,就会从轻量级锁阶段升级成重量级锁阶段。

(3)重量级锁阶段

此处的轻量级锁是用挂起等待的方式实现的,当有很多线程同时去竞争这个锁时,有个线程拿到锁了,其他线程没拿到,就不会再不断的重复尝试去拿锁,而是阻塞等待,等待一段时间再去尝试拿锁,不成功再阻塞等待一段时间,循环以上步骤,这题就会让出cpu的资源,可以利用这些cpu资源干一些其他的事。

注意:此处只能升级,不能降级,但是只是当前版本是这样的,以后的版本也说不好会添加降级的功能。

2、锁消除

也是synchronized的内部优化;有时候,有些代码可以一眼看上去就不用加锁,但是代码加锁了,这时候,编译器就会把这个锁给干掉,毕竟加锁操作也是要消耗一些硬件资源的。

注意:锁消除和偏向锁的区别

        锁消除:针对能够一眼就看出不涉及到线程安全问题的代码,编译器能够把锁给消除掉。

        偏向锁:是已经运行代码了,才知道没有锁竞争。

3、锁粗化

通常情况下,我们更偏好于让锁更细一些,这样更有利于并发编程的时候解决线程安全问题,但有时候,让锁更粗写能提高效率,会希望锁粗点。

锁粗化:把多个细粒度的锁合并成一个粗粒度的锁。

如图:

一段代码中,频繁的加锁解锁,肯定会消耗更多的硬件资源,但是如果能把一段代码这些加锁解锁操作,优化成只有一次加锁、解锁,这样也能提高效率。而锁粗化目的也是提高效率。

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

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

相关文章

mybatis 的快速入门以及基于spring boot整合mybatis(一)

MyBatis基础 MyBatis是一款非常优秀的持久层框架,用于简化JDBC的开发 准备工作: 1,创建sprong boot工程,引入mybatis相关依赖2,准备数据库表User,实体类User3, 配置MyBatis(在applic…

高德地图画渐变线

高德地图画渐变线,思路是将线和颜色均分为多个小线段和小颜色,实现渐变,类似于下图。 如果需要多段线,自己循环拼一下就可以了,方法返回多个小线段组成的polyline数组。 /** 高德地图画渐变线* author: liyun* params…

记一次由 jedis 引发的离谱选学问题

背景 我的应用中,使用 jedis 作为连接 redis 的客户端,一直在用的好好的,后来有一个新的组件,也需要使用 redis,但是组件是内部封装的,我只能提供一个 StringReidsTempalte,所以我基于应用本身…

GPTs的创建与使用,自定义GPTs中的Actions示例用法 定义和执行特定任务的功能模块 通过API与外部系统或服务的交互

Name 等 Logo:自动生成 Name 介绍 Description 介绍 Instructions 要求或命令等 比如用中文回复,角色。 Knowledge 上传你的知识库,如果你有某一垂直行业的数据,基于数据来回答。比如我有某个芯片的指令集。 Capabilities 都要 Actions&…

ELasticsearch:什么是语义搜索?

语义搜索定义 语义搜索是一种解释单词和短语含义的搜索引擎技术。 语义搜索的结果将返回与查询含义匹配的内容,而不是与查询中的单词字面匹配的内容。 语义搜索是一组搜索引擎功能,其中包括根据搜索者的意图及其搜索上下文理解单词。 此类搜索旨在通过…

算法Day15 农场耕作

农场耕作 Description 你是一位农夫,拥有一块 m x n 的小农场。你打算在这块农场上耕种不同的农作物,以便在季节结束时获得最大的收成。 农场被分割成网格,每个格子代表不同的耕种区域,你可以选择每次向下或向右移动一格来耕作。…

解决 Element-ui中 表格(Table)使用 v-if 条件切换后,表格的列的筛选不显示了

解决方法 在每个需要使用 v-if 或 v-else 的 el-table-column 上增加 key 作为唯一标识,这样渲染的时候就不会因为复用原则导致列数据混乱了。关于key值,一般习惯使用字段名,也可随机生成一个值,只要具有唯一性就可以。

离散型制造企业MES系统行业应用

离散型制造企业具有产品种类多、生产周期长、生产过程复杂等特点,因此,采用先进的生产管理系统对于提高企业的生产效率和管理水平至关重要。其中,制造执行系统(MES)在离散型制造企业中得到了广泛应用, 一、…

RedisTemplate操作哈希数据

RedisTemplate操作哈希数据 概述常用方法添加哈希数据添加hashMap值判断hashkey 获取哈希数据获取属性值获取hashMap值。获取键值对。获取map键是否有值判断是否有map键。获取键。获取长度。集合方式获取值。匹配获取键值对 自增以double值大小自增。以long值大小自增。 修改删…

node.js和npm的安装与环境配置(2023最新版)

目录 安装node.js测试是否安装成功测试npm环境配置更改环境变量新建系统变量 安装node.js 1、进入官网下载:node.js官网 我选择的是windows64位的,你可以根据自己的实际情况选择对应的版本。 2、下载完成,安装。 打开安装程序 接受协议 选…

浅谈5G基站节能及数字化管理解决方案的设计与应用-安科瑞 蒋静

截至2023年10月,我国5G基站总数达321.5万个,占全国通信基站总数的28.1%。然而,随着5G基站数量的快速增长,基站的能耗问题也逐渐日益凸显,基站的用电给运营商带来了巨大的电费开支压力,降低5G基站的能耗成为…

js 复制粘贴板,当clipboardjs 不好使怎么办?

最近项目中做一个很常见的复制粘贴的功能耽误了比较长的时间特此记录&#xff0c;在往常这个功能直接用 clipboard 做就行了&#xff0c;但是这次却发现复制功能不好使了&#xff0c;虽然走了复制成功的回调&#xff0c;但是粘贴板并没有复制的内容。代码如下 <div v-for&q…

使用LangSmith来快速学习LangChain

好风凭借力&#xff0c;送我上青云&#xff01; 什么是LangSmith LangSmith is a platform for building production-grade LLM applications. It lets you debug, test, evaluate, and monitor chains and intelligent agents built on any LLM framework and seamlessly int…

oracle12c的job没有自动执行,手动运行提示任务1%正在运行问题

有个oracle12c上的job&#xff0c;提交到dbms_job&#xff0c;不知道什么时候开始&#xff0c;停下来了&#xff0c;没有自动运行。 手动关闭这个job&#xff0c;重新打开&#xff0c;不行&#xff1b;删除JOB&#xff0c;重新创建&#xff0c;也不行。 参考拙作&#xff1a; …

Leetcode 39 组合总和

题意理解&#xff1a; 一个 无重复元素 的整数数组 candidates 和一个目标整数 target 从candidates 取数字&#xff0c;使其和 target &#xff0c;有多少种组合&#xff08;candidates 中的 同一个 数字可以 无限制重复被选取&#xff09; 这道题和之前一道组合的区别&am…

【USB、串口、COM口、TTL、RS-232、RS-485区别详解】

USB&#xff0c;串口&#xff0c;COM口&#xff0c;TTL&#xff0c;RS-232&#xff0c;RS-485区别详解 1. USB&#xff0c;串口&#xff0c;COM口&#xff0c;TTL&#xff0c;RS-232&#xff0c;RS-485区别详解2 USB转TTL2 RS-232转TTL3 USB4 UART5 STM32串口异步通讯需要定义的…

2024年AI视频识别技术的6大发展趋势预测

随着人工智能技术的快速发展&#xff0c;AI视频识别技术也将会得到进一步的发展和应用。2023年已经进入尾声&#xff0c;2024年即将来临&#xff0c;那么AI视频识别技术又将迎来怎样的发展趋势&#xff1f;本文将对2023年的AI视频技术做一个简单的盘点并对2024年的发展趋势进行…

c/c++中一些不常用但有用的知识

1.变长数组 bool fun(int cnt) {unsigned char data[cnt];return true; } 在 C 语言中&#xff0c;变长数组&#xff08;Variable Length Arrays&#xff0c;VLA&#xff09;是 C99 标准引入的特性&#xff0c;允许使用变量来定义数组的长度。因此&#xff0c;在 C 版本的代码…

Oauth2.0 认证

目录 前言 1.介绍 2.Oauth2.0过程详解 3.Oauth 整合到 Spring Boot 实践 4.方法及配置详解&#xff1a; 总结 前言 Oauth2.0 是非常流行的网络授权表准&#xff0c;已经广泛应用在全球范围内&#xff0c;比较大的公司&#xff0c;如腾讯等都有大量的应用场景。 1.介绍 …