锁机制 -- 概述篇

锁机制

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

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

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

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

相关文章

原子变量原理剖析

一、原子操作 原子操作保证指令以原子的方式执行&#xff0c;执行过程不被打断。先看一个实例&#xff0c;如下所示&#xff0c;如果thread_func_a和thread_func_b同时运行&#xff0c;执行完成后&#xff0c;i的值是多少&#xff1f; // test.c static int i 0;void thread…

013、MongoDB常用操作命令与高级特性深度解析

目录 MongoDB常用操作命令与高级特性深度解析 1. 数据库操作的深入探讨 1.1 数据库管理 1.1.1 数据库统计信息 1.1.2 数据库修复 1.1.3 数据库用户管理 1.2 数据库事务 2. 集合操作的高级特性 2.1 固定集合(Capped Collections) 2.2 集合验证(Schema Validation) 2.…

自组装mid360便捷化bag包采集设备

一、问题一&#xff1a;电脑太重&#xff0c;换nuc 采集mid360数据的过程中&#xff0c;发现了头疼的问题&#xff0c;得一手拿着电脑&#xff0c;一手拿着mid360来采集&#xff0c;实在是累胳膊。因此&#xff0c;网购了一个intel nuc, 具体型号是12wshi5000华尔街峡谷nuc12i…

Python私教张大鹏 PyWebIO通过事件回调实现表格的编辑和删除功能

从上面可以看出&#xff0c;PyWebIO把交互分成了输入和输出两部分&#xff1a;输入函数为阻塞式调用&#xff0c;会在用户浏览器上显示一个表单&#xff0c;在用户提交表单之前输入函数将不会返回&#xff1b;输出函数将内容实时输出至浏览器。这种交互方式和控制台程序是一致的…

在Ubuntu 18.04.6 LTS 交叉编译生成Windows 11下的gdb 8.1.1

1. 安装mingw sudo apt-get install mingw-w64 2. 下载 gdb 8.1.1源码 https://ftp.gnu.org/gnu/gdb/gdb-8.1.1.tar.gz 解压命令 tar -xf gdb-8.1.1.tar.gz 进入目录,创建build目录: hq@hq:~/gdb-8.1.1/build$ 执行配置 ../confi

视频云计算的未来发展趋势:智能化、个性化与云端协同助力智慧城市安防监控

随着信息技术的飞速发展&#xff0c;云计算作为一种全新的服务模式&#xff0c;正在改变我们处理数据和信息的方式。而视频云计算技术&#xff0c;作为云计算领域的一个重要分支&#xff0c;以其独特的优势&#xff0c;正在逐步渗透到我们生活的各个领域。 一、视频云计算技术…

[leetcode hot 150]第一百二十二题,买卖股票的最佳时机Ⅱ

题目&#xff1a; 给你一个整数数组 prices &#xff0c;其中 prices[i] 表示某支股票第 i 天的价格。 在每一天&#xff0c;你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买&#xff0c;然后在 同一天 出售。 返回 你能获得的 最大…

javaScript利用indexOf()查找字符串的某个字符出现的位置

1 创建字符串 2 利用indexof()查询字符串的字符 3 利用while循环判断indexOf是否等于-1&#xff0c;不等于-1就打印一次并且索引号1去查下一个字符 //创建字符串var str1234567812311231;var indexstr.indexOf(1);//查询该字符while(index !-1)//indexOf()没有查到会返回-1{…

企业本地大模型用Ollama+Open WebUI+Stable Diffusion可视化问答及画图

最近在尝试搭建公司内部用户的大模型,可视化回答,并让它能画图出来, 主要包括四块: Ollama 管理和下载各个模型的工具Open WebUI 友好的对话界面Stable Diffusion 绘图工具Docker 部署在容器里,提高效率以上运行环境Win10, Ollama,SD直接装在windows10下, 然后安装Docker…

Linux中彩色打印

看之前关注下公众号呗 第1部分&#xff1a;引言 1.1 Python在文本处理中的重要性 Python作为一种广泛使用的高级编程语言&#xff0c;以其简洁的语法和强大的功能在文本处理领域占有一席之地。无论是数据清洗、自动化脚本编写&#xff0c;还是复杂的文本分析&#xff0c;Py…

甄选范文“论云上自动化运维及其应用”,软考高级论文,系统架构设计师论文

论文真题 云上自动化运维是传统IT运维和DevOps的延伸,通过云原生架构实现运维的再进化。云上自动化运维可以有效帮助企业降低IT运维成本,提升系统的灵活度,以及系统的交付速度,增强系统的可靠性,构建更加安全、可信、开放的业务平台。 请围绕“云上自动化运维及其应用”…

Typora failed to export as pdf. undefined

变换版本并没有用&#xff0c;调整图片大小没有用 我看到一个博客后尝试出方案 我的方法 解决&#xff1a;从上图中的A4&#xff0c;变为其他&#xff0c;然后变回A4 然后到处成功&#xff0c;Amazing&#xff01; 参考&#xff1a; Typora 导出PDF 报错 failed to export…

识图生成代码:通义千问vsGPt4o,有点小崩

今日对比一下通义千问和GPt4o&#xff0c;在通过识别图片然后去生成前端代码 在当今ai的时代&#xff0c;通过ai去生成页面的代码可以很大的提高我们的开发效率下面是我们要求的生成的图片截图&#xff0c;这是掘金的榜单 效果对比 首先我们使用通义千问&#xff0c;让他去帮我…

Tesseract Python 图片文字识别入门

1、安装tesseract Index of /tesseract https://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-w64-setup-v5.3.0.20221214.exe 2、安装中文语言包 https://digi.bib.uni-mannheim.de/tesseract/tessdata_fast/ 拷贝到C:\Program Files\Tesseract-OCR\tessdata 3、注…

Linux基础 - BIND加密传输缓存服务器

目录 零. 简介 一. 安装 二. 安全的加密传输 三. 部署缓存服务器 四. 总结 零. 简介 BIND&#xff08;Berkeley Internet Name Domain&#xff09;是一款广泛使用的开源 DNS&#xff08;域名系统&#xff09;服务器软件。 域名系统的主要作用是将易于人类理解的域名&…

《昇思25天学习打卡营第12天 | 昇思MindSpore基于MindSpore的GPT2文本摘要》

12天 本节学习了基于MindSpore的GPT2文本摘要。 1.数据集加载与处理 1.1.数据集加载 1.2.数据预处理 2.模型构建 2.1构建GPT2ForSummarization模型 2.2动态学习率 3.模型训练 4.模型推理

Windows怎么实现虚拟IP

在做高可用架构时&#xff0c;往往需要用到虚拟IP&#xff0c;在linux上面有keepalived来实现虚拟ip的设置。在windows上面该怎么弄&#xff0c;keepalived好像也没有windows版本&#xff0c;我推荐一款浮动IP软件PanguVip&#xff0c;它可以实现windows上面虚拟ip的漂移。设置…

MySQL学习(3):SQL语句之数据定义语言:DDL

1.SQL通用语法与分类 &#xff08;1&#xff09;通用语法 &#xff08;2&#xff09;分类 2.DDL 2.1数据库操作 show DATABASES; #查询所有数据库select DATABASE(); #查询当前数据库create DATABASE 数据库名称 [default charest 字符集] [collate 排列规则]; #default cha…

43.三倍游戏

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/390 题目描述 三倍游戏是一种单人游戏。玩…

3d模型怎么一缩放模型都散了?---模大狮模型网

在3D建模和渲染中&#xff0c;缩放是常见的操作&#xff0c;用来调整模型的大小以适应不同场景或视角需求。然而&#xff0c;有时在进行缩放操作时&#xff0c;模型可能会出现不希望的散乱现象&#xff0c;这可能导致模型的外观和结构受到影响。模大狮将探讨为何会出现这种问题…