锁策略详解:互斥锁、读写锁、乐观锁与悲观锁、轻量级锁与重量级锁、自旋锁、偏向锁、可重入锁与不可重入锁、公平锁与非公平锁


一.锁策略

锁策略指的是在多线程编程中用于管理共享资源访问的规则和技术。它们确保在任何给定时间只有一个线程可以访问共享资源,以防止竞态条件和数据不一致性问题。常见的锁策略包括:

  1. 互斥锁(Mutex):最常见的锁类型,用于确保同一时刻只有一个线程可以访问共享资源。其他线程必须等待当前线程释放锁。

  2. 读写锁(ReadWriteLock):允许多个线程同时读取共享资源,但只有一个线程可以写入共享资源。这有助于提高并发性能,因为读取操作不会阻塞其他读取操作。

  3. 悲观锁(Pessimistic Locking):假设会发生并发访问,因此在访问共享资源之前先获取锁。适用于写入操作频繁的场景。

  4. 乐观锁(Optimistic Locking):假设不会发生并发访问,因此在提交更改时检查是否有其他线程已经修改了资源。适用于读取操作频繁,且冲突不经常发生的场景。

  5. 自旋锁(Spin Lock):在获取锁时不会阻塞线程,而是使用循环等待直到锁可用。适用于短期占用情况,避免了线程切换的开销。

  6. ... ...

选择合适的锁策略需要根据具体的应用场景和性能要求来决定。不同的锁策略有不同的开销和适用场景,需要根据实际情况进行权衡和选择。

二.互斥锁

互斥锁(Mutex,Mutual Exclusion)是一种用于多线程编程的同步机制,用于确保在任何给定时间只有一个线程可以访问共享资源。互斥锁提供了两个主要操作:锁定(lock)和解锁(unlock)。在访问共享资源之前,线程需要先获取锁;在访问完成后,需要释放锁,以允许其他线程访问该资源。

互斥锁的特点包括:

  1. 互斥性:同一时间只有一个线程可以持有互斥锁,其他线程必须等待当前线程释放锁后才能获取锁。
  2. 阻塞:当一个线程尝试获取一个已经被其他线程持有的互斥锁时,该线程会被阻塞,直到获取到锁为止。
  3. 锁定状态:互斥锁可以有两种状态:锁定和未锁定。只有持有锁的线程才能访问共享资源。
  4. 安全性:互斥锁可以确保在多线程环境下对共享资源的安全访问,避免了竞态条件和数据不一致性问题。

在C/C++中,互斥锁通常由pthread_mutex_t表示,可以使用pthread_mutex_lock来获取锁,pthread_mutex_unlock来释放锁。在Java中,可以使用synchronized关键字来实现互斥锁的功能,也可以使用ReentrantLock类来实现互斥锁。

三.读写锁

读写锁(ReadWriteLock)是一种并发控制机制,允许多个线程同时读取共享资源,但在写入时需要互斥,即只能有一个线程进行写操作,且写操作时禁止读取操作。读写锁的主要目的是在读操作频繁、写操作较少的情况下提高并发性能。

读写锁有两种状态:读取锁和写入锁。在读取锁状态下,多个线程可以同时获取读取锁,从而允许并发读取操作。在写入锁状态下,只有一个线程可以获取写入锁,其他线程无法获取读取或写入锁,直到写入操作完成。

读写锁的特点包括:

  1. 读写分离:读取操作不会阻塞其他读取操作,但会阻塞写入操作。这样可以提高读取操作的并发性能。

  2. 写入互斥:写入操作会阻塞其他读取和写入操作,确保在写入操作时不会有其他线程对共享资源进行读取或写入。

  3. 公平性:读写锁可以是公平的,即按照请求锁的顺序分配锁;也可以是非公平的,即允许插队获取锁。

Java中的读写锁由ReentrantReadWriteLock实现,读写锁特别适合于 "频繁读, 不频繁写" 的场景中。

  • ReentrantReadWriteLock.ReadLock 类表示一个读锁,这个对象提供了 lock / unlock 方法进行加锁解锁
  • ReentrantReadWriteLock.WriteLock 类表示一个写锁,这个对象也提供了 lock / unlock 方法进行加锁解锁

四.乐观锁与悲观锁

乐观锁(Optimistic Locking)和悲观锁(Pessimistic Locking)是两种不同的并发控制机制,用于处理多线程环境下的数据访问冲突。

  1. 乐观锁(Optimistic Locking)

    • 乐观锁的核心思想是假设在大多数情况下,数据并发访问冲突的概率很低,因此不需要加锁。在读取数据时,不会加锁,而是在尝试更新数据时才会进行检查。
    • 在使用乐观锁时,通常会在读取数据时记录下数据的版本号或者时间戳,在尝试更新数据时检查这个版本号或者时间戳是否发生变化。如果没有变化,则说明在读取到写入之间数据没有被其他线程修改,可以进行更新操作;如果发生变化,则表示数据被修改过,需要进行冲突处理,如回滚或者重试等。
    • 乐观锁适用于读操作频繁、写操作相对较少的场景,可以减少锁竞争,提高并发性能。
  2. 悲观锁(Pessimistic Locking)

    • 悲观锁的核心思想是假设在数据访问时会发生并发冲突,因此在访问数据之前先加锁,确保在任何时候只有一个线程可以访问数据,其他线程需要等待。
    • 悲观锁适用于写操作频繁的场景,可以有效避免数据被并发修改而导致的问题。常见的悲观锁实现包括互斥锁(Mutex)和读写锁(ReadWriteLock)等。

总的来说,乐观锁适合于并发写入比较少、并发读取比较多的场景,可以提高系统的并发性能;而悲观锁适合于并发写入比较频繁的场景,可以保证数据的一致性和完整性。选择合适的锁策略取决于具体的应用场景和需求。

举个例子来说

同学 A 认为 "老师是比较忙的, 我来问问题, 老师不一定有空解答"。因此同学 A 会先给老师发消息: "老师你忙嘛? 我下午两点能来找你问个问题嘛?" (相当于加锁操作) 得到肯定的答复之后,才会真的来问问题。 如果得到了否定的答复,那就等一段时间,下次再来和老师确定时间。这个是悲观锁。

同学 B 认为 "老师是比较闲的, 我来问问题, 老师大概率是有空解答的"。因此同学 B 直接就来找老师(没加锁, 直接访问资源) 如果老师确实比较闲,那么直接问题就解决了。如果老师这会确实很忙,那么同学 B 也不会打扰老师,就下次再来(虽然没加锁,但是能识别出数据访问冲突)。这个是乐观锁。

这两种思路不能说谁优谁劣,而是看当前的场景是否合适。如果当前老师确实比较忙,那么使用悲观锁的策略更合适,使用乐观锁会导致 "白跑很多趟", 耗费额外的资源。如果当前老师确实比较闲, 那么使用乐观锁的策略更合适,使用悲观锁会让效率比较低。

五.重量级锁与轻量级锁

轻量级锁和重量级锁是 Java 虚拟机中用于实现锁的两种不同策略,主要针对 synchronized 关键字所提供的锁的不同实现方式。

  1. 轻量级锁(Lightweight Lock)

    • 轻量级锁是为了在多线程竞争情况下,提高性能而引入的一种锁优化技术。当一个线程尝试获取锁时,如果锁没有被其他线程占用,虚拟机会在当前线程的栈帧中使用 CAS 操作尝试将对象头部的 Mark Word 替换为指向当前线程的锁记录指针(Lock Record Pointer)。
    • 如果 CAS 操作成功,当前线程就获得了锁,并且锁的状态被标记为轻量级锁。此时其他线程访问同步块时会尝试自旋等待,而不是直接阻塞,以减少线程切换的开销。
    • 如果自旋等待一段时间后仍无法获取锁,或者其他线程争用激烈,CAS 操作失败,那么轻量级锁会膨胀为重量级锁。
  2. 重量级锁(Heavyweight Lock)

    • 当轻量级锁膨胀失败时,锁会升级为重量级锁。重量级锁会使其他线程阻塞,而不是进行自旋等待,防止CPU空转浪费资源。
    • 重量级锁的实现通常是通过操作系统的互斥量(Mutex)来实现的,当一个线程获取了锁,其他线程就无法获取锁,只能在等待队列中等待锁释放。

总的来说,轻量级锁适用于线程竞争不激烈的情况,可以减少线程切换的开销,提高性能;而重量级锁适用于线程竞争激烈的情况,可以保证数据的一致性和完整性。 Java 虚拟机会根据锁竞争的情况自动选择合适的锁实现方式。

六.自旋锁

自旋锁是一种基于循环重试的锁机制,在多线程编程中用于实现对共享资源的互斥访问。当一个线程尝试获取自旋锁时,如果锁已被其他线程持有,该线程不会立即进入阻塞状态,而是在循环中不断尝试获取锁,直到成功获取为止,或者达到最大尝试次数后才会放弃。

自旋锁的主要特点包括:

  1. 循环等待:获取自旋锁的线程会在一个循环中不断尝试获取锁,直到成功或者达到一定的尝试次数。
  2. 忙等待:自旋锁的获取过程是忙等待的,即线程在等待锁的过程中会一直占用CPU资源。
  3. 无阻塞:自旋锁的获取过程不会使线程进入阻塞状态,适用于对锁的占用时间较短的情况。
  4. 性能:自旋锁适用于锁竞争不激烈、等待锁时间较短的情况,可以减少线程切换的开销,提高性能。
  5. 等待限时:为了避免自旋锁的线程一直占用CPU资源,通常会设置一个最大尝试次数或者超时时间,超过这个限制后线程会放弃自旋并进入阻塞状态等待锁的释放。

自旋锁在并发度高、锁竞争不激烈的情况下可以有效地提高性能,但在锁竞争激烈、持有锁时间较长的情况下,自旋锁可能会导致性能下降。因此,在选择锁机制时需要根据实际情况进行权衡和选择。在Java中,java.util.concurrent包提供了ReentrantLock的实现,其中包括了可重入锁和自旋锁的功能。

七.偏向锁

偏向锁是Java虚拟机为了减少无竞争情况下的同步原语的性能消耗而引入的一种优化手段。当一个线程访问同步块时,如果该同步块没有被锁定或者被其他线程锁定,那么这个线程会尝试获取偏向锁,并将对象头中的标记设置为指向自己的线程ID。之后,当这个线程再次进入同步块时,不需要再次获取锁,因为对象头中已经记录了这个线程已经获取了偏向锁。

偏向锁适用于大多数情况下都是单线程访问同步块的场景,因为在这种情况下,偏向锁可以显著减少获取锁的代价。但是,如果有其他线程竞争锁,那么偏向锁会失效,对象会膨胀为重量级锁,这样会增加获取锁的代价。

偏向锁的优点包括:

  1. 减少同步操作的耗时,提高程序性能;
  2. 对于无竞争的场景,减少不必要的线程切换。

需要注意的是,偏向锁只适用于无竞争的情况,如果存在竞争,会导致额外的性能损失。因此,在使用偏向锁时,需要根据实际场景进行评估和选择。

八.公平锁与非公平锁

公平锁和非公平锁是两种不同的锁获取策略,用于多线程环境下对共享资源的访问控制。

  1. 公平锁

    • 公平锁是指多个线程按照请求锁的顺序获取锁,即先到先得的原则。当一个线程尝试获取公平锁时,如果锁当前被其他线程持有,该线程会进入等待队列,按照先来后到的顺序等待锁的释放。
    • 公平锁保证了锁的获取是按照请求的顺序进行的,避免了某些线程长时间无法获取到锁的情况,确保了线程获取锁的公平性。
  2. 非公平锁

    • 非公平锁是指多个线程尝试获取锁时,并不考虑锁的等待队列中是否有等待线程,而是直接尝试获取锁。如果锁当前未被其他线程持有,则获取成功;如果锁已被其他线程持有,则当前线程可能会被阻塞,也可能会一直尝试获取锁。
    • 非公平锁相比于公平锁,可能会导致某些线程长时间无法获取到锁,存在一定的不公平性。但由于不需要维护等待队列的顺序,非公平锁的性能通常会比公平锁更好。

在Java中,ReentrantLockReentrantReadWriteLock可以指定为公平锁或非公平锁。在创建锁时,可以通过构造方法来指定锁的公平性。公平锁在一定程度上保证了线程获取锁的顺序,适用于对锁的公平性有要求的场景;而非公平锁则更适用于对性能要求较高,可以容忍一定程度的不公平性的场景。

九.可重入锁与不可重入锁

可重入锁(Reentrant Lock)和不可重入锁是两种锁的概念,主要区别在于同一个线程能否多次获取同一把锁。

  1. 可重入锁

    • 可重入锁是指同一个线程可以多次获取同一把锁,而不会发生死锁。线程每次获取锁时,锁的计数器会加一;每次释放锁时,计数器会减一。只有当计数器为零时,锁才会被完全释放。
    • 可重入锁的一个典型应用场景是方法递归调用。当一个同步方法内部调用同一个类的其他同步方法时,如果没有可重入锁,就会发生死锁。而可重入锁能够保证线程在递归调用时不会被自己阻塞。
  2. 不可重入锁

    • 不可重入锁是指同一个线程不能多次获取同一把锁。如果一个线程已经持有了某个锁,再次尝试获取该锁时会被阻塞,直到锁被释放。
    • 不可重入锁在一些情况下可能会导致死锁,因为线程在持有锁的情况下又试图获取同一把锁,会造成自己阻塞而无法释放已持有的锁。

Java中的synchronized关键字实现的锁是可重入锁,即同一个线程可以重复获取同一把锁。而ReentrantLock也是可重入锁的一种实现。可重入锁能够简化并发编程中对锁的使用,避免了一些潜在的死锁情况,提高了程序的可靠性和健壮性。




 本次的分享就到此为止了,希望我的分享能给您带来帮助,创作不易也欢迎大家三连支持,你们的点赞就是博主更新最大的动力!如有不同意见,欢迎评论区积极讨论交流,让我们一起学习进步!有相关问题也可以私信博主,评论区和私信都会认真查看的,我们下次再见

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

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

相关文章

导航app为什么知道还有几秒变绿灯?

在使用地图导航app行驶至信号灯的交叉路口时,这些应用程序会贴心地告知用户距信号灯变化还有多少秒,无论是即将转为绿灯还是红灯。这一智能化提示不仅使得驾驶员能适时做好起步或刹车的准备,有效缓解了因等待时间不确定而产生的焦虑情绪&…

活动预告|“AI+Security”系列第1期:大模型网络空间安全前沿探索活动火热报名中

由Wisemodel社区、安全极客主办的 “AISecurity”系列第1期: 大模型网络空间安全前沿探索 线下活动 将于2024年5月18日下午14:00 在苏州街16号神州数码大厦5层举行 本活动旨在汇聚业界专家和实践者共同探讨和推进AI自身安全、AI赋能安全与AI给安全带来的挑战等关…

Blender动画与云渲染:创造高质量作品的未来路径

Blender作为开源的3D图形软件,在多个领域广受欢迎。但随着项目复杂度提升,传统渲染方式受限。云渲染技术的兴起突破了这些限制,为创作者提供了更自由、高效的创作环境。 一、Blender动画项目的挑战 传统上,Blender动画渲染需要依…

【C语言】深度解析:动态内存管理的机制与实践

🔥引言 本篇将深度解析:动态内存管理的机制。为了更加灵活分配内存中的空间,库中为了我们提供了一些的函数,去动态开辟和释放堆上的空间。 🌈个人主页:是店小二呀 🌈C语言笔记专栏:C语言笔记 &a…

【Redis】Redis入门概述

😀大家好,我是白晨,一个不是很能熬夜😫,但是也想日更的人✈。如果喜欢这篇文章,点个赞👍,关注一下👀白晨吧!你的支持就是我最大的动力!&#x1f4…

选择数据摆渡系统 哪个厂家比较好?

数据摆渡系统是一种用于在不同网络或安全域之间安全传输数据的技术解决方案。它通常用于解决网络隔离环境下的数据交换问题,确保数据在传输过程中的安全性、完整性和合规性。数据摆渡系统可以采用物理手段,如通过专用隔离硬件和私有安全协议,…

数据结构的二叉树(c语言版)

一.二叉树的概念 1.二叉树的基本概念 二叉树是一种常见的树状数据结构,它由若干个节点组成,这些节点通过边连接起来。每个节点最多可以有两个子节点,分别称为左子节点和右子节点。 二叉树的特点是每个节点最多有两个子节点,而且…

上海市青少年算法2023年12月月赛(丙组)试题解析

上海市青少年算法2023年12月月赛(丙组)试题解析 T1数砖数 题目描述 给定一种 22 规格的瓷砖,该瓷砖的式样为 ## .# 用这种瓷砖,从平面的左上角出发,将整个平面铺满,形如: 给定两个整数 n 与 m,请计算从左上角开始的 n 行 m 列的区域中,有多少格子是 #。 输入格式 第一…

易百纳与成都鼎桥达成战略合作,共创海鸥派生态新篇章

前言 易百纳技术社区(以下简称“易百纳”)与成都鼎桥通信技术有限公司(以下简称“成都鼎桥”)达成共建海鸥派的周边生态战略合作。基于海鸥派推出的鼎桥TD OS嵌入式发行版1.0,为海鸥派生态注入新的活力。 易百纳 Eba…

机器人增量学习研究综述

源自:控制与决策 作者:马旭淼 徐德 “人工智能技术与咨询” 发布 摘 要 机器人的应用场景正在不断更新换代,数据量也在日益增长.传统的机器学习方法难以适应动态的环境,而增量学习技术能够模拟人类的学习过程,使机器人能利用旧知识来加快新任务的…

数据分析处理的步骤是什么?制造业企业如何挑选数据分析处理软件?看这篇就够了

随着工业4.0的深入实施以及国家对制造业高质量发展战略的日益强调,工业数据已经崭露头角,成为生产经营活动中至关重要的核心要素。不仅如此,工业数据还作为优质的生产要素,为新兴生产力的形成提供了强有力的支撑,从而推…

docker自建GitLab仓库

摘要 GitLab 是一个功能强大的开源代码托管平台,它不仅提供了代码存储和版本控制的核心功能,还集成了项目管理、CI/CD 流水线、代码审查等企业级特性。本文将指导你如何在自己的服务器上搭建 GitLab 社区版,创建一个完全属于自己的开源仓库&…

Linux基础命令(续)

17,wc命令 作用:统计行数、单词数、字符个数 格式: wc 选项 文件 wc passwd 26 36 1159 passwd26:行数 36:单词数 1159:字符数 passwd:文件名wc autofs.conf 426 2604 15137 autofs.conf426…

某攻防演练心得之随笔记

最近太忙了,忙于各种奇奇怪怪的事情,有攻防,有应急,有渗透,还成为了一段时间内的“word高级工程师”......有师傅说我现在更新的越来越慢了,是呀,其实我也不知道怎么了,每天各种新闻…

用balenaEtcher烧录ubuntu的iso文件都失败,所以选用了另一种烧录的软件Rufus,然后烧录成功了+安装ubuntu的坑

https://releases.ubuntu.com/bionic/进入网页下载ubuntu 选择烧录软件将下载的Ubuntu烧录到U盘中 之前用这个U盘烧录过一次,成功了,后来应该是U盘受损或者是什么其他原因使得用这个U盘总是烧录失败 换思路:由于一直使用balenaEtcher烧录ubu…

《四月女友》开启预售 “不想错过”鼓励情侣找回消失的爱

电影《四月女友》由中国电影集团公司进口,中国电影股份有限公司发行、译制,改编自川村元气同名小说,山田智和导演,佐藤健、长泽雅美、森七菜主演。《四月女友》今日发布“不想错过”版预告,预告中,佐藤健饰…

【论文阅读笔记】HermesSim(Code is not Natural Language) (Security 24)

个人博客地址 HermesSim [Security 24] 论文:《Code is not Natural Language: Unlock the Power of Semantics-Oriented Graph Representation for Binary Code Similarity Detection》 仓库:https://github.com/NSSL-SJTU/HermesSim 提出的问题 二…

Pyhton专题学习资料包,Python从入门到精通全套学习资料[30G]

资源概览 百本Python学习书籍大礼包百本前端学习书籍大礼包微专业-数据挖掘分析之Python篇小甲鱼零基础入门学习Python(全96集) 资源获取 🧑‍💻【Pyhton专题资料】【30G】 百本Python书籍## 百本前端书籍 微专业-数据挖掘分析之Python篇 预备课【先…

【问题解决】记一个“奇怪”的java.lang.NoSuchMethodError错误

问题现象 近期本人负责的一个SpringBoot模块出现了java.lang.NoSuchMethodError报错,问题情况如下: A类提供了setJumpType(String type),B类调用A类的setJumpType(String type)报错java.lang.NoSuchMethodError: com.xxx.A.setJumpType(Lja…

北京软考职称、入户相关疑问解答

很多考生考软考证书是为了职称和入户,那么北京软考证书可以用于入户吗?软考职称认定有什么条件? 北京软考职称如何认定? 从以上图片描述我们可以知道,北京软考职称认定是有学历、资历要求的。北京近两年的“职称评审通…