锁机制 -- 概述篇

锁机制

1、概述

​  加锁是为了解决并发场景下,多个线程对同一资源同时进行操作,而导致同一线程多次操作出现结果不唯一的情况(一次操作包含多条指令)。结果不唯一发生的原因在于指令的错乱,前提条件是多线程环境及多个线程的执行顺序是无序的。对于资源A来说,有一次操作[A++] (内包含了多条指令:指令1,读取A的值;指令2,将A的值加1;指令3,将结果值重新赋予A),某一时刻,线程1执行了指令1,2,将要执行指令3时,线程2开始执行,并执行完了指令1,这样最终结果A的值只加了1;另一时刻,线程1执行完了指令1,2,3,线程2再执行指令1,2,3,这样最终结果A的值就加了2。同一操作,不同时刻,最终的结果却不唯一的现象发生了。

​  此时要引出原子性这一概念了,指某一操作已达到最小级别不可继续划分,对于上述操作[A++]来说就,该操作就不是原子性操作,而对于操作[读A的值](内只包含了一条指令:读取A的值)就是原子性操作。

​  而加锁的本质就是通过保证了线程执行操作的有序性,进而保证了操作的原子性。加锁通过对一次操作做出限制,多个线程同时执行该操作时,如若已有线程进行操作,则其他线程必须等待该线程完成后才可进行操作,且一次只允许一个线程进行操作。如此,对于线程来说,该操作是原子性的。

​ 1. 对于 Java 来说,锁机制总体可分为两种,synchronized 关键字和 Lock 接口。

  • synchronized 关键字,可用于修饰普通方法、代码块、静态方法。

  • Lock 接口,定义了lock、lockInterruptibly、tryLock、unlock、newCondition等方法。

​ 2. 对于 MySQL 来说,锁机制总体可分为两种,读锁和写锁,也可称为共享锁和排他锁。

  • 读锁,lock in share mode,允许多个事务对同一行数据加读锁。
  • 写锁,for update,只允许一个事务对同一行数据加写锁,且加写锁之后也不能再加读锁。

​ 3. 对于 Redis 来说,虽然没有直接提供加锁的方式,但提供了 setnx 这一命令可供我们实现加锁。

  • setnx,设置一个 key-value 键值对,如果 key 不存在,则 value 设置成功,并返回 1;如果 key 已存在,则 value 设置失败,并返回 0。

2、Java 中的锁

案例:读写操作下的并发问题

public class LockTest {private Integer count = 0;public static void main(String[] args) throws InterruptedException {LockTest lockTest = new LockTest();ExecutorService executorService = Executors.newFixedThreadPool(10);for (int i = 0; i < 10; i++) {executorService.execute(lockTest::operate);}executorService.shutdown();TimeUnit.HOURS.sleep(1);}private void operate() {try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}// 读操作if (count == 0) {// 写操作count = 1;System.out.println(Thread.currentThread().getName() + " 加锁成功!");}}}

在这里插入图片描述

2.1、使用 synchronized

    private void operate() {try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}// 加锁synchronized (this) {// 读操作if (count == 0) {// 写操作count = 1;System.out.println(Thread.currentThread().getName() + " 加锁成功!");}}}

在这里插入图片描述

2.2、使用 ReentrantLock 类

    private final ReentrantLock lock = new ReentrantLock();private void operate() {try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}// 加锁lock.lock();try {// 读操作if (count == 0) {// 写操作count = 1;System.out.println(Thread.currentThread().getName() + " 加锁成功!");}} finally {lock.unlock();}}

在这里插入图片描述

2.3、使用 ReentrantReadWriteLock 类

    private final ReentrantReadWriteLock.WriteLock lock = new ReentrantReadWriteLock().writeLock();private void operate() {try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}// 加锁lock.lock();try {// 读操作if (count == 0) {// 写操作count = 1;System.out.println(Thread.currentThread().getName() + " 加锁成功!");}} finally {lock.unlock();}}

在这里插入图片描述

2.4、使用 StampedLock 类

    private final StampedLock stampedLock = new StampedLock();private void operate() {try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}// 加锁long stamp = stampedLock.writeLock();try {// 读操作if (count == 0) {// 写操作count = 1;System.out.println(Thread.currentThread().getName() + " 加锁成功!");}} finally {stampedLock.unlockWrite(stamp);}}

在这里插入图片描述

2.5、使用 Semaphore 类

    private final Semaphore semaphore = new Semaphore(1);private void operate() {try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}try {// 加锁semaphore.acquire();// 读操作if (count == 0) {// 写操作count = 1;System.out.println(Thread.currentThread().getName() + " 加锁成功!");}} catch (InterruptedException e) {e.printStackTrace();} finally {semaphore.release();}}

在这里插入图片描述


3、MySQL 中的锁
# 查看事务自动提交是否开启
SHOW VARIABLES LIKE 'autocommit';
# 开启事务自动提交
SET autocommit = 1;
# 关闭事务自动提交
SET autocommit = 0;
# 查看未提交的事务
SELECT * FROM performance_schema.events_transactions_current WHERE STATE = 'ACTIVE';
# 开启事务
BEGIN;
或者 
START TRANSACTION;
# 提交事务
COMMIT;
# 回滚事务
ROLLBACK;

注:MySQL的行锁是在事务结束时自动释放的。

3.1、读锁,lock in share mode

# 事务A
select scene_id, scene_name from scene 
where scene_id = 13
lock in share mode;# 事务B
select scene_name, scene_logo from scene 
where scene_id = 13
lock in share mode;

在这里插入图片描述
在这里插入图片描述

3.2、写锁,for update

# 事务A
select scene_id, scene_name from scene
where scene_id = 13
for update ;# 事务B
select scene_name, scene_logo from scene
where scene_id = 13
for update ;select scene_name, scene_logo from scene 
where scene_id = 13
lock in share mode;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


4、Redis 中的锁

4.1、setnx

# 第一次操作
setnx lock-flag 1# 第二次操作
setnx lock-flag 0

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

k8s_如何查看container拉取的镜像

当 Kubernetes (k8s) 使用 containerd 作为容器运行时时,可以通过以下方法查看 Kubernetes 集群中拉取的镜像。可以直接在每个节点上使用 containerd 的命令行工具 ctr 来查看已经拉取的镜像。 方法一:使用 ctr 查看节点上的镜像 确保 containerd 已安装并运行: 在 Kuberne…

全面解析:微软Edge浏览器支持的PDF文件操作功能

微软Edge浏览器&#xff0c;作为Windows 10及更高版本操作系统的默认浏览器&#xff0c;不仅提供了快速、安全的网页浏览体验&#xff0c;还内置了对PDF文件的多种操作功能。本文将详细探讨Edge浏览器支持的PDF文件操作&#xff0c;帮助用户更有效地利用这一功能强大的浏览器。…

双指针算法第一弹(移动零 复写零 快乐数)

目录 前言 1. 移动零 &#xff08;1&#xff09;题目及示例 &#xff08;2&#xff09;一般思路 &#xff08;3&#xff09;双指针解法 2. 复写零 &#xff08;1&#xff09;题目及示例 &#xff08;2&#xff09;一般解法 &#xff08;3&#xff09;双指针解法 3. 快…

61.ThreadLocal认识和使用

ThreadLocal介绍 ThreadLocal类用来提供给线程内部的局部变量。 这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。 ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文。 ThreadLocal的作用…

MySQL之索引创建原则

索引创建原则有哪些&#xff1f; 1.针对数据量较大&#xff0c;且查询比较频繁的表建立索引。&#xff08;单表超过10w数据&#xff09; 2.针对常作为查询条件&#xff08;where&#xff09;、排序&#xff08;order by&#xff09;、分组&#xff08;group by&#xff09;操…

Hadoop 安装与伪分布的搭建

目录 1 SSH免密登录 1.1 修改主机名称 1.2 修改hosts文件 1.3 创建hadoop用户 1.4 生成密钥对免密登录 2 搭建hadoop环境与jdk环境 2.1 将下载好的压缩包进行解压 2.2 编写hadoop环境变量脚本文件 2.3 修改hadoop配置文件&#xff0c;指定jdk路径 2.4 查看环境是否搭建完成 3 …

Clickhouse 常见操作

数据查询 从json array string中解析字段 json array string 为json.dumps(array(dict)) select JSONExtractString(row,"Date") as Date from( select arrayJoin(JSONExtractArrayRaw(Remarks)) as row from table x )JSONExtractArrayRaw&#xff1a; 将JsonS…

python中的相对路径

在Python中&#xff0c;相对路径是相对于当前工作目录&#xff08;由os.getcwd()返回&#xff09;的路径。当你想要引用当前目录、父目录或子目录中的文件或目录时&#xff0c;你会使用相对路径。 以下是一些常见的相对路径写法&#xff1a; 引用当前目录下的文件或目录&#…

C# Modbus设备信息加载的实现方式(2)

GlobalProperties是一个全局的数据&#xff0c;类似CoreData&#xff1a; public class GlobalProperties{public static Device Device { set; get; }public static Action<int, string> AddLog;public static SysAdmin CurrentAdmin;public static ModbusTCP Modbus { …

基于Spring Boot的药房信息管理系统

1 项目介绍 1.1 研究的背景及意义 随着社会的飞速进步和药房行业竞争的白热化&#xff0c;传统的手工管理模式已难以适应药房信息管理的现代化需求。在计算机科学技术日臻完善的背景下&#xff0c;药房信息管理者们日益认识到运用计算机技术进行信息管理的迫切性和重要性。计…

【Git】LFS

什么是lfs Git 是分布式 版本控制系统&#xff0c;这意味着在克隆过程中会将仓库的整个历史记录传输到客户端。对于包涵大文件&#xff08;尤其是经常被修改的大文件&#xff09;的项目&#xff0c;初始克隆需要大量时间&#xff0c;因为客户端会下载每个文件的每个版本**。Gi…

快手正式推出Vision Pro版本,引领虚拟现实社交新潮流

6月28日&#xff0c;快手正式推出其专为Apple Vision Pro打造的版本——快手vp版app&#xff0c;成为国内首批登陆Apple Vision Pro的短视频平台。 借助先进的虚拟现实技术&#xff0c;用户可以在快手上体验更真实生动的视频内容&#xff0c;无论是观看趣味短视频内容&#xf…

产品是应该有生命力的

产品是应该有生命力的 在日新月异的商业环境中&#xff0c;产品被寄予厚望&#xff0c;不仅仅满足基本功能需求&#xff0c;而是要能够自我革新&#xff0c;适应市场和技术的快速变化&#xff0c;以及持续吸引并留住用户。 这种生命力体现在产品的迭代升级能力、对用户需求的精…

[鹏城杯 2022]babybit

发现一个压缩包提取出来提取出来两个压缩包里面是注册表使用MiTeC Windows Registry Recovery 恢复注册表 flag在ROOT\ControlSet001\Control\FVEStats里的OsvEncryptInit和OsvEncryptComplete中 NSSCTF{2022/6/13_15:17:39_2022/6/13_15:23:46}

互联网信任危机:Perplexity搜索引擎如何破坏内容创作者的权益

前段时间&#xff0c;Perplexity搜索引擎还是一颗冉冉升起的明日之星&#xff0c;手握巨额投资&#xff0c;有很美好的未来前景&#xff0c;这时&#xff0c;如果不出意外的话&#xff0c;要出意外。 喜好儿网 Perplexity这家公司&#xff0c;它正试图通过创建一个新型的“答…

LoRaWAN网关源码分析(基础概念篇)

目录 一、简介 1、lora_gateway 2、packet_forwarder 二、目录结构 1、lora_gateway 2、packet_forwarder 一、简介 LoRaWAN网关的实现主要依赖两个源代码&#xff1a;lora_gateway和packet_forwarder。接下来&#xff0c;我们将从分析源代码入手&#xff0c;移植LoRaWAN源…

LeetCode:经典题之21、24 题解及延伸

系列目录 88.合并两个有序数组 52.螺旋数组 567.字符串的排列 643.子数组最大平均数 150.逆波兰表达式 61.旋转链表 160.相交链表 83.删除排序链表中的重复元素 389.找不同 1491.去掉最低工资和最高工资后的工资平均值 896.单调序列 206.反转链表 92.反转链表II 141.环形链表 …

深入探讨目标检测算法:原理、方法与应用

目录 1. 目标检测的基本原理 1.1 分类与定位 1.2 评价指标 2. 常见目标检测算法 2.1 传统方法 2.2 基于深度学习的方法 2.2.1 区域提议方法 2.2.2 单阶段检测方法 3. 目标检测算法的发展历程 3.1 早期阶段 3.2 深度学习时代 4. 目标检测的实际应用 4.1 自动驾驶 …

网页背景全屏就这?分享 1 段优质 CSS 代码片段!

大家好&#xff0c;我是大澈&#xff01; 本文约 700 字&#xff0c;整篇阅读约需 1 分钟。 每日分享一段优质代码片段。 今天分享一段 CSS 代码片段&#xff0c;使用 CSS 设置网页全屏背景图片&#xff0c;很简单。 老规矩&#xff0c;先阅读代码片段并思考&#xff0c;再看…

Android Focused Window的更新

启动App时更新inputInfo/请求焦点窗口流程&#xff1a; App主线程调ViewRootImpl.java的relayoutWindow()&#xff1b;然后调用到Wms的relayoutWindow()&#xff0c;窗口布局流程。焦点窗口的更新&#xff0c;通过WMS#updateFocusedWindowLocked()方法开始&#xff0c;下面从这…