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


一.锁策略

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

  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也是可重入锁的一种实现。可重入锁能够简化并发编程中对锁的使用,避免了一些潜在的死锁情况,提高了程序的可靠性和健壮性。




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

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

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

相关文章

王者营地ip地址怎么隐藏

在数字化快速发展的今天,网络安全和隐私保护成为了每个人都需要面对的重要问题。作为一款备受欢迎的游戏社区应用,王者营地为用户提供了丰富的游戏信息和交流平台。然而,与此同时,用户的IP地址也可能在不经意间被泄露,…

spring框架定时任务(@Scheduled)

内容: 在spring框架中,scheduled注解是用于声明定时任务的,以最简单的方式来创建定时任务。 注意: 要使用scheduled注解,需要确保已下几点: 1.spring应用程序已经开启了定时任务的开启。需要在配置类&am…

博客互动革命:如何打造活跃读者社区并提升参与度

CSDN 的朋友你们好,我是未来,今天给大家带来专栏【程序员博主教程(完全指南)】的第 10 篇文章“与读者互动”。本文揭示了提升技术博客参与度的秘诀。从评论互动到社交媒体策略,本文将指导你如何建立强大的读者社区。掌…

MYSQL数据库-SQL语句

数据库相关概念 名称全称简称数据库存储数据的仓库,数据是有组织的进行存储DataBase(DB)数据库管理系统操纵和管理数据库的大型软件DataBase Management System(DBMS)SQL操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准Structured Quer…

win10电脑录屏全攻略,从入门到精通,一篇文章就够了!

在当今科技时代,电脑录屏已经成为人们生活中越来越重要的一部分。无论是工作还是娱乐,我们都可能需要录制电脑屏幕来保存或分享一些内容。在本文中,我们将向您介绍win10电脑录屏的三种方法,并对每种方法进行详细说明,为…

宝塔安装多个版本的PHP,如何设置默认的PHP版本

如何将默认的PHP版本设置为7.3.32, 创建软链接指向7.3版本,关键命令:ln -sf /www/server/php/73/bin/php /usr/bin/php 然后再查看PHP版本验证一下结果 [rootlocalhost ~]# ln -sf /www/server/php/73/bin/php /usr/bin/php [rootlocalho…

青蒿素优化算法(AO)-2024年新算法-公式原理详解与性能测评 Matlab代码免费获取

声明:文章是从本人公众号中复制而来,因此,想最新最快了解各类智能优化算法及其改进的朋友,可关注我的公众号:强盛机器学习,不定期会有很多免费代码分享~ 目录 原理简介 一、初始化阶段 二、综合淘汰阶…

2024创业热门选择:短视频带货,轻资产模式引领你飞翔

在当今这个信息爆炸的时代,短视频带货已经成为了一种全新的商业模式,为创业者提供了前所未有的机遇。特别是在2024年,短视频带货的潜力愈发显现,成为众多创业者的热门选择。本文将深入探讨 keJ0277 短视频带货的魅力所在&#xff…

element ui的确认提示框按钮样式修改

修改确认提示框的默认按钮样式,使用css强制修改 例: js代码: this.$confirm("您确定要删除吗?此操作无法撤销并且将永久删除所有数据。", "提示", { type: "warning", cancelButtonClass: "…

日本率先研发成功6G设备,刺痛了谁?为何日本能率先突破?

日本率先研发成功6G设备,无线数据速率是5G的百倍,这让日本方面兴奋莫名,毕竟日本在科技方面从1990年代以来太缺少突破的创新了,那么日本为何如今在6G技术上能率先突破呢? 日本在1980年代末期达到顶峰,它的科…

【算法】dfs

快乐的流畅:个人主页 个人专栏:《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火,在为久候之人燃烧! 文章目录 引言一、全排列1. 决策树2. 设计代码1. 全局变量2. dfs函数3. 细节问题 二、子集解法一1. 决策树2. 设计代码…

PCB的盘中孔

目录 一、什么时候可以在焊盘上打孔? 二、什么时候可以在焊盘上打孔? 绘制PCB时经常会遇到空间不够无法走线,这时我们会放置过孔使信号线穿过电路板一侧到达另一侧进行走线,这样既方便走线,也能够节省板子空间。有时…

Linux提权--第三方软件MYSQL数据库提权(WEB+本地)

免责声明:本文仅做技术交流与学习,非法搞事后果自负... 目录 靶场镜像: 过程: 手工: 下载mysql udf poc 进行编译. 进入数据库进行UDF导出 下载(上传) 创建do_system函数调用 探针(./LinEnum.sh),查找suid权限. 配合使用find调用执行 工具: 过程: 外连不上? 隧道出…

气膜建筑电源配置是怎样的—轻空间

在气膜建筑中,电源配置是确保建筑控制系统连续运行的重要组成部分。以下是该建筑的电源配置方案: 1. 市电供电与备用发电机: 为了应对市电中断等突发情况,系统采用市电供电与备用柴油发电机双重供电方式。这种配置保证了即使在市电…

UV胶的应用场景有哪些?

UV胶是一种特殊的胶水,其固化过程需要紫外光照射。它具有快速固化、高强度、无溶剂挥发等优点,因此在许多应用场景中被广泛使用。UV胶的应用场景非常广泛,包括但不限于以下几个方面: 1.电子产品组装: UV胶在电子产品的组装中扮演…

高校课程评价|基于SSM+vue的高校课程评价系统的设计与实现(源码+数据库+文档)

高校课程评价系统 目录 基于SSM+vue的高校课程评价系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1管理员功能模块 2学生功能 3教师功能 4专家功能 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&…

企业微信hook接口协议,ipad协议http,格式化发送@消息

格式化发送消息 参数名必选类型说明uuid是String每个实例的唯一标识,根据uuid操作具体企业微信send_userid是long要发送的人或群idisRoom是bool是否是群消息 请求示例 {"uuid":"1688853790599424","send_userid":1069605295501613…

实验0.0 Visual Studio 2022安装指南

Visual Studio 2022 是一个功能强大的开发工具,对于计算机专业的学生来说,它不仅可以帮助你完成学业项目,还能为你将来的职业生涯打下坚实的基础。通过学习和使用 Visual Studio,你将能够更高效地开发软件,并在编程领域…

Alibaba SpringCloud集成Nacos、openFeign实现负载均衡-15

Spring cloud alibaba Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。 主要功能 服务限流降级:默认支持 WebS…

Unity生命周期函数详解

Unity生命周期函数详解 Unity生命周期函数是Unity引擎中用于控制游戏对象行为的一系列方法。它们在游戏的不同阶段被自动调用,允许开发者在适当的时机执行特定的代码。了解和正确使用生命周期函数对于创建流畅和高效的游戏至关重要。 生命周期函数概述 Unity生命…