常见的各种锁总结

article/2025/3/17 13:05:00

常见的各种锁
一、常见锁简单说明
1、悲观锁
悲观锁认为自己在使用数据的时候一定有别的线程来修改数据,在获取数据的时候先加锁,确保数据的安全性。
锁实现:关键字synchronized、Lock接口的实现
使用场景:写操作比较多,先加锁可以保证写操作时数据正确
2、乐观锁
乐观锁认为自己在使用数据的时候不会被别的线程修改,所以不会添加锁,只是在更新的时候去判断之前有没有别的线程更改过这个数据
锁实现:CAS算法,例如AtomicInteger类的原子自增底层是通过CAS实现的
使用场景:读多,不加锁的特点能够使读的性能大幅度提升

3、读锁(共享锁)
读锁即共享锁(S锁):共享 (S) 用于不更改或不更新数据的操作(只读操作),如 SELECT 语句。
4、写锁(排他锁)
写锁即排他锁(X锁):用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。确保不会同时同一资源进行多重更新。
5、行锁
行锁即对数据表中每一行数据加锁,数据库最细粒度的锁,开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高
实现:InnoDB

6、表锁
表锁即对数据库中每个表加锁,数据库中最大级别的锁,开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低
实现:MyISAM、BDB、InnoDB
7、页锁
页锁即对组加锁,对相邻数据加锁,数据库中介于表锁和行锁之间的锁,开销和加锁速度介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般
实现:BDB

8、互斥锁(重量级锁或阻塞同步、悲观锁)
互斥锁是一个互斥的同步对象,意味着同一时间有且仅有一个线程可以获取它,互斥锁可适用于一个共享资源每次只能被一个线程访问的情况
9、自旋锁(CAS)
自旋锁在申请资源但是申请不到的情况下并不会挂起,而是会选择持续申请。这种锁结果适用于每个线程占用较少时间的锁,并且线程阻塞状态切换的代价远高于等待的代价时使用。
10、分布式锁
在很多场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务、分布式锁等。有的时候,我们需要保证一个方法在同一时间内只能被同一个线程执行。
实现:数据库实现分布式锁; 缓存(Redis等)实现分布式锁; Zookeeper实现分布式锁;
11、区间锁(分段锁)
ConcurrentHashMap jdk1.7使用了分段锁来保证线程安全,效率比起使用synchronized的HashTable要高的很多。每个集合都可以看作是一个存储东西的房子,HashTable与ConcurrentHashMap存储的都是HashEntry数组(每个数组里面是链表,暂且忽略,直到就好)
12、重入锁
重入锁当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的 ,可避免死锁
锁实现:关键字synchronized,ReentrantLock锁实现
13、非重入锁
非重入锁与可重入锁相反,不可递归调用,递归调用就发生死锁。
锁实现:NonReentrantLockk锁实现
14、公平锁
公平锁多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。
锁实现:ReentrantLock(true)锁实现
优点:所有的线程都能得到资源,不会饿死在队列中。
缺点:吞吐量会下降很多,队列里面除了第一个线程,其他的线程都会阻塞,cpu唤醒阻塞线程的开销会很大。
15、非公平锁
非公平锁多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。
优点:可以减少CPU唤醒线程的开销,整体的吞吐效率会高点,CPU也不必取唤醒所有线程,会减少唤起线程的数量。
缺点:1、你们可能也发现了,这样可能导致队列中间的线程一直获取不到锁或者长时间获取不到锁,导致饿死2、会发生羊群效应
二、synchronized 关键锁
1、synchronized 锁升级 jdk1.6后做了优化
其实每个java对象都可以是一个锁对象包括对方法加锁,其实JVM底层也是对对象的class进行加锁,java对象在jvm内存中存储分为三部分:
1、对象头(主要是运行时的数据)
2、实例数据
3、填充数据
对象头里面的数据简单如下
长度 内容 说明

32/64bit	Mark Work	hashCode,GC分代年龄,锁信息32/64bit	Class Metadata Address	指向对象类型数据的指针32/64bit	Array Length	数组的长度(当对象为数组时)

从上图可以看出java中每个对象都能成为锁对象,改对象的锁信息存储在jvm内存中的对象头的markword中当创建一个对象后如下图,偏向锁标志位01,状态为0表示改对象还没有加上偏向锁,(1表示改对象加上了偏向锁),即该对象初始化完成后就有了偏向锁的标志位,这也说明了所有的对象是可偏向的,同时也说明了刚创建的对象偏向锁是没有生效的
bit fields	偏向锁标志	锁标志位hash	0	01

偏向锁生效
线程执行到临界区(critical section)时,此时会利用CAS(Compare and Swap)操作,将线程ID插入到Markword中,同时修改偏向锁的标志位。
所谓临界区,就是只允许一个线程进去执行操作的区域,即同步代码块。CAS是一个原子性操作
此时的Mark word的结构信息如下:
在这里插入图片描述

此时偏向锁的状态为“1”,说明对象的偏向锁生效了,同时也可以看到,哪个线程获得了该对象的锁。
如果此对象已经偏向了,并且不是偏向自己,则说明存在了竞争。此时可能就要根据另外线程的情况,可能是重新偏向,也有可能是做偏向撤销,但大部分情况下就是升级成轻量级锁了。
锁膨胀
当出现有两个线程来竞争锁的话,那么偏向锁就失效了,此时锁就会膨胀,升级为轻量级锁。这也是我们经常所说的锁膨胀

锁撤销

由于偏向锁失效了,那么接下来就得把该锁撤销,锁撤销的开销花费还是挺大的,其大概的过程如下
1、在一个安全点停止拥有锁的线程。
2、遍历线程栈,如果存在锁记录的话,需要修复锁记录和Markword,使其变成无锁状态。3、唤醒当前线程,将当前锁升级成轻量级锁。
所以,如果某些同步代码块大多数情况下都是有两个及以上的线程竞争的话,那么偏向锁就会是一种累赘,对于这种情况,我们可以一开始就把偏向锁这个默认功能给关闭
轻量级锁
锁撤销升级为轻量级锁之后,那么对象的Markword也会进行相应的的变化。下面先简单描述下锁撤销之后,升级为轻量级锁的过程:
1、线程在自己的栈桢中创建锁记录 LockRecord。
2、将锁对象的对象头中的MarkWord复制到线程的刚刚创建的锁记录中。
3、将锁记录中的Owner指针指向锁对象。
4、将锁对象的对象头的MarkWord替换为指向锁记录的指针。

bit fields	锁标志位指向LockRecord的指针	00

注:锁标志位”00”表示轻量级锁
轻量级锁主要有两种
1、自旋锁(jdk1.4~jdk1.6之前 默认自旋10次,可以通过jvm参数自行设置) 2、自适应自旋锁(jdk1.6起jvm自己来计算自旋升级逻辑)
自旋锁
所谓自旋,就是指当有另外一个线程来竞争锁时,这个线程会在原地循环等待,而不是把该线程给阻塞,直到那个获得锁的线程释放锁之后,这个线程就可以马上获得锁的。
注意,锁在原地循环的时候,是会消耗cpu的,就相当于在执行一个啥也没有的空循环。
所以,轻量级锁适用于那些同步代码块执行的很快的场景,这样,线程原地等待很短很短的时间就能够获得锁了。
经验表明,大部分同步代码块执行的时间都是很短很短的,也正是基于这个原因,才有了轻量级锁
自适应自旋锁

所谓自适应自旋锁就是线程空循环等待的自旋次数并非是固定的,而是会动态着根据实际情况来改变自旋等待的次数。
假如一个线程1刚刚成功获得一个锁,当它把锁释放了之后,线程2获得该锁,并且线程2在运行的过程中,此时线程1又想来获得该锁了,但线程2还没有释放该锁,所以线程1只能自旋等待,但是虚拟机认为,由于线程1刚刚获得过该锁,那么虚拟机觉得线程1这次自旋也是很有可能能够再次成功获得该锁的,所以会延长线程1自旋的次数。
另外,如果对于某一个锁,一个线程自旋之后,很少成功获得该锁,那么以后这个线程要获取该锁时,是有可能直接忽略掉自旋过程,直接升级为重量级锁的,以免空循环等待浪费资源。
重量级锁
轻量级锁膨胀之后,就升级为重量级锁了。重量级锁是依赖对象内部的monitor锁来实现的,而monitor又依赖操作系统的MutexLock(互斥锁)来实现的,所以重量级锁也被成为互斥锁。
当轻量级所经过锁撤销等步骤升级为重量级锁之后,它的Markword部分数据大体如下
在这里插入图片描述

为什么说重量级锁开销大呢主要是,当系统检查到锁是重量级锁之后,会把等待想要获得锁放在队列中排队阻塞,被阻塞的线程不会消耗cup。但是阻塞或者唤醒一个线程时,都需要操作系统来执行,这就需要从用户态转换到内核态,而转换状态是需要消耗很多时间的,有可能比用户执行代码的时间还要长。这就是说为什么重量级线程开销很大的。
三、CAS锁
在这里插入图片描述


http://chatgpt.dhexx.cn/article/dUT3ZDK4.shtml

相关文章

BioGRID 互作数据库

01 — BioGRID BioGRID 是 Biological General Repository for Interactionh Datasets 的缩写(网址为 https://thebiogrid.org),是一个公开的数据库,主要记录、整理包括蛋白、遗传和化学互作的数据,涵盖人类和所有主要…

Fuzzing论文:Reinforcement Learning-based Hierarchical Seed Scheduling for Greybox Fuzzing

Reinforcement Learning-based Hierarchical Seed Scheduling for Greybox Fuzzing 整体内容论文内容多级代码覆盖指标(用于种子聚类)分层种子调度策略实验 论文题目Reinforcement Learning-based Hierarchical Seed Scheduling for Greybox Fuzzing工具…

BIO的理解

前言 bio:b有两说,一为base,jdk中最早抽象出的io体系;一为block,jdk 1.0 中的io体系是阻塞的。所以两说皆有道理,一般我们认为b取block之意 nio:n也有两说,一为new,针对…

BIO初步学习

1.一个服务端一个客户端 具体代码实现 服务端 public class Server {public static void main(String[] args) {try {ServerSocket serverSocket new ServerSocket(9999);Socket socket serverSocket.accept();InputStream inputStream socket.getInputStream();Buffered…

12.BIO详解

Java BIO 就是传统的 java io 编程, 其相关的类和接口在 java.io 中. BIO 编程简单流程 服务器端启动一个 ServerSocket.客户端启动 Socket 对服务器进行通讯, 默认情况下服务器需要对每个客户建立一个县线程与之通讯.客户端发出请求后, 先咨询服务器是否有线程响应, 如果没有…

bioinformatics小技巧

文章目录 1. 软件安装1.1 linux上python2的安装1.2 Mercurial 安装及使用1.3 tRNAscan的安装和使用1.4 Linux上安装miniconda 2.数据下载2.1 linux上通过ftp下载一个文件夹下的全部文件2.2 GEO数据库数据下载 3.操作系统3.1 Windows下将R设置为环境变量。3.2 Linux 下怎样快速查…

brat标注的ann文件,转为BIO序列标注

这个地方真的好少有人写到,踩了好久的坑都不知道怎么解决。 首先,在用brat自带的转换序列标注的文件时,运行程序 1、python2 anntoconll.py ../data/data_new/corpoa.txt 报错: File "anntoconll.py", line 154, in…

BIO学习笔记

视频地址:https://www.bilibili.com/video/BV1gz4y1C7RK?fromsearch&seid15021234423448500976 2. JAVA BIO深入剖析 Java BIO 就是传统的 java io 编程,其相关的类和接口在 java.io。 BIO(blocking I/O) : 同步阻塞,服务器…

BIO实例

使用 BIO 模型编写一个服务器端,监听 6666 端口,当有客户端连接时,就启动一个线程与之通讯。要求使用线程池机制改善,可以连接多个客户端.服务器端可以接收客户端发送的数据(telnet 方式即可)。 图 代码演示: package…

利用 bioconda 管理生物信息软件

利用 bioconda 管理生物信息软件 如需视频讲解,请移步:一只小蛮要 【要知道 bioinfo】利用 bioconda 管理生物信息软件 1 了解 conda,anaconda,miniconda,bioconda 1.1 conda conda是一个软件模块管理工具&#xff…

IMex和IntAct数据库简介

欢迎关注微信公众号《生信修炼手册》! 蛋白质相互作用的数据库非常的多,比如DIP, MINT, IntAct, BioGRID等,不同数据库中的信息存在了大量的冗余,而且在不同数据库之间进行检索也非常的费力,为了减少不同数据库的冗余&#xff0c…

【Bio】基础生物学 - 基因 gene

文章目录 1. DNA 脱氧核糖核酸、RNA 核糖核酸1.1 核苷酸1.2 脱氧核糖核酸1.3 核糖核酸 2. 基因2.1 基因组2.2 染色体2.3 基因与脱氧核苷酸的牵连2.4 基因与DNA的牵连2.5 基因与染色体的牵连 Ref 1. DNA 脱氧核糖核酸、RNA 核糖核酸 1.1 核苷酸 核苷酸 (Nucleotide) \blue{\tex…

Bioedit 使用

1. 下载: 地址一搜就有,软件界面如下 BioEdit Download - Research software utility for creating and editing biological sequences 2. 酶切位点分析 构建过表达质粒、双荧光素酶质粒必用功能。以人的MYOD1基因为例 ,分析酶切位点。 &…

BIO~~

BIO~~ 第一章 Java的I/O演进之路2.1 I/O 模型基本说明2.2 I/O模型Java BIOJava NIOJava AIO 2.3 BIO、NIO、AIO 适用场景分析 第三章 JAVA BIO深入剖析3.1 Java BIO 基本介绍3.2 Java BIO 工作机制3.3 传统的BIO编程实例回顾客户端案例如下服务端案例如下小结 3.4 BIO模式下多发…

python处理数据的一些代码

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、如何读取txt文件,将其转化为DataFrame格式二、给DataFrame添加列名三、删除指定行四、读取csv文件,不让第一行成为列名五、读取DataFram…

BioGRID:蛋白质相互作用数据库

欢迎关注微信公众号《生信修炼手册》! BioGRID数据库是一个老牌经典的蛋白质相互作用数据库,在今年9月份刚刚分布了最新版本3.5.165,该版本从66,164篇文献中整理出了1,607,037个蛋白质相互作用,28,093个嵌合体信息以及726,378个转录后修饰PTM…

(NCRE网络技术)中小型网络系统总体规划与设计方法-知识点

欢迎您阅读此系列文章,文章参考自《全国计算机等级考试三级教程.网络技术》。内容为NCRE三级网络技术主要知识点以及常考点,此知识点总结参照《三级网络技术考试大纲(2018年版)》。阅读此系列文章可以帮助您快速、轻松考取相应证书!祝您阅读愉…

Linux系统如何查看服务器带宽及网络使用情况

文章目录 前言  linux查看服务器带宽具体方法  一、使用speedtest-cli命令查看下载和上传最大流量值  二、查看网卡、网络的详情   1.查看服务器网络端口   2.ethtool命令查看宽带大小 三、nload命令实时统计网卡带宽使用率  四、dstat -n命令实时监测网络的状态…

计算机网络的组成及其逻辑结构

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、计算机网络的组成 计算机系统: 数据通信系统 网络软件及网络协议 二、计算机网络的逻辑结构 资源子网 通信子网 总结 前言 计算机网络是在20世纪6…

Linux中centos修改系统时间并写到硬件,Linux中centos设置定时自动同步网络时间

文章目录 前言一、centos修改系统时间并写到硬件1.1查看当前的系统时间1.2修改系统时间1.3查看硬件时间1.4同步系统时间和硬件时间1.5本地时间写入硬件时间 二、centos设置定时自动同步网络时间2.1安装ntpdate工具2.2CentOS安装/操纵crontab2.3启动crontab并查看状态2.4写一个c…