锁机制 -- 概述篇

锁机制

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,一经查实,立即删除!

相关文章

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

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

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 …

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

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

快手正式推出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源…

Android Focused Window的更新

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

MIX OTP——监督树和应用

在上一章关于 GenServer 的内容中&#xff0c;我们实现了 KV.Registry 来管理存储容器。在某个时候&#xff0c;我们开始监控存储容器&#xff0c;这样每当 KV.Bucket 崩溃时&#xff0c;我们就能采取行动。虽然变化相对较小&#xff0c;但它提出了一个 Elixir 开发人员经常问的…

独家原创 | Matlab实现CNN-Transformer多变量时间序列预测

SCI一区级 | Matlab实现BO-Transformer-GRU多变量时间序列预测 目录 SCI一区级 | Matlab实现BO-Transformer-GRU多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现CNN-Transformer多变量时间序列预测&#xff1b; 2.运行环境为Matlab2023b…

【JavaScript】JavaScript简介

希望文章能给到你启发和灵感&#xff5e; 如果觉得文章对你有帮助的话&#xff0c;点赞 关注 收藏 支持一下博主吧&#xff5e; 阅读指南 JavaScript入门&#xff08;1&#xff09;————JavaScript简介开篇说明一、什么是JavaScript二、JavaScript的使用2.1 开发工具的选择…

fiddler抓包工具

概念 概念&#xff1a; Fiddler是一个http协议调试代理工具&#xff0c;它能够记录并检查所有你的电脑和互联网之间的http通讯。 http&#xff1a;不加密&#xff0c;端口为80 https&#xff1a;加密&#xff0c;端口为443 原理&#xff1a; 其实就在访问服务器时&#xff0…

如何在写代码中找到乐趣

平时我们写代码呢&#xff0c;多数情况都是流水线式写代码&#xff0c;基本就可以实现业务逻辑了。 如何在写代码中找到乐趣呢&#xff0c;我觉得&#xff0c;最好的方式就是&#xff1a;使用设计模式优化自己的业务代码。 参考资料&#xff1a; 实战&#xff01;工作中常用到…

[方法] Unity 3D模型与骨骼动画

1. 在软件中导出3D模型 1.1 3dsmax 2014 1.1.1 TGA转PNG 3dsmax的贴图格式为tga&#xff0c;我们需要在在线格式转换中将其转换为Unity可识别的png格式。 1.1.2 模型导出 导出文件格式为fbx。在导出设置中&#xff0c;要勾选三角算法&#xff0c;取消勾选摄像机和灯光&#…

三秒4张图!让 Stable Diffusion 出图速度暴增的新一代生成模型LCM!

前言 大家好&#xff0c;这里是和你们一起探索 AI绘画月月~ 最近一种新的图像生成形式逐渐兴起&#xff0c;即生成的图像会随输入的文字或笔画动作迅速变化&#xff0c;这让图像生成有了更多灵活探索和准确控制的空间。这种「实时反馈」的感觉源于模型能在几秒钟内&#xff0…

fiddler 返回Raw乱码

有时会发现自己发送的请求后&#xff0c;返回结果Raw里面是乱码&#xff0c;可以勾选Decode并重新发送请求就解决了 这个时候将Decode勾选一下 此时就好了

【C++ | 委托构造函数】委托构造函数 详解 及 例子源码

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

模版总结小全

BFS 最短步数问题 #include<iostream> #include<queue> #include<cstring> using namespace std;const int N 50; char g[N][N],d[N][N]; int dx[] {-1,0,1,0}; int dy[] {0,1,0,-1}; int n,m;int bfs(int x,int y){queue<pair<int,int> > q…

MySQL高级-SQL优化-insert优化-批量插入-手动提交事务-主键顺序插入

文章目录 1、批量插入1.1、大批量插入数据1.2、启动Linux中的mysql服务1.3、客户端连接到mysql数据库&#xff0c;加上参数 --local-infile1.4、查询当前会话中 local_infile 系统变量的值。1.5、开启从本地文件加载数据到服务器的功能1.6、创建表 tb_user 结构1.7、上传文件到…