【InnoDB 存储引擎】15.7.1 InnoDB Locking(锁实验,包含了如 记录锁、间隙锁、Next-Key Lock 算法等,重要)

news2024/11/13 14:57:08

文章目录

  • 1 关于 Record Lock 的实验
    • 1.1 实验 1:没有主键时的如何锁定
    • 1.2 实验 1(续):带着问题继续实验
    • 1.3 实验 2:有主键时如何锁定
  • 2 关于 Next-Key Lock 的实验
    • 2.1 实验 3:如何确定算法的锁定范围
    • 2.2 实验 4:降序索引下,算法的锁定范围
    • 2.3 实验 5:幻读实验(Next-Key Lock 与 幻读)
  • 3 实验总结与疑问
  • 4 参考资料

前言:实验环境:mysql 版本 8.0.26 ,其他环境如 5.7 或许有很小的不同但关系不大!

实验目的:加深对锁相关理论知识的理解,理解锁理论的自然性😋

作者写这个实验方案花费了不小的精力,希望看官们点赞转发评论点 Stat 支持一下

1 关于 Record Lock 的实验

Record Lock 总是会去锁住索引记录,如果 InnoDB 存储引擎表在建立的时候没有设置任何一个索引,那么这时 InnoDB 存储引擎会使用隐式的主键来进行锁定

1.1 实验 1:没有主键时的如何锁定

实验步骤如下:

  1. 环境准备
-- 准备表
CREATE TABLE `t1` (
 `id` int NOT NULL,
 `name` varchar(200) DEFAULT NULL
);
-- 准备数据(id值不要全部连续)
INSERT INTO `t1` ( `id` , `name` ) VALUES (10, 'aaa');
INSERT INTO `t1` ( `id` , `name` ) VALUES (12, 'bbb');
INSERT INTO `t1` ( `id` , `name` ) VALUES (14, 'ccc');
  1. 开启一个客户端执行 行记录锁定
-- 1、开启一个事务
begin;
-- 2、锁定 id 为 12 的行
select * from t1 where id = 12 for update;
  1. 观察 performance_schema.data_Lock 表中的内容

观察图中情况:

1、可以看到存在一个表锁和多个行锁

2、关于表锁

  1. LOCK_TYPE 为 TABLE 表明是表锁
  2. LOCK_MODE 是 IX 是意向锁。关于意向锁这里不做解释,当其他事务要对全表的数据进行加锁时,那么就不需要判断每一条数据是否被加锁了
  3. 表锁锁定的是全表,所以 LOCK_DATA 是空,INDEX_NAME 为空

3、关于行锁

  1. LOCK_TYPE 为 RECORD 表明是行锁
  2. 索引名称 GEN_CLUST_INDEX 是自动生成的聚簇索引(因为你没有指定主键)
  3. 锁定模式 LOCK_MODE 是排它锁
  4. 在 LOCK_DATA 字段发现把我们插入的 3 条记录全部锁定了,锁定的内容是自动生成的的 RowID。在一个表没有指定主键时,mysql 会为每行生成 RowID,占用 8 个字节,详细内容参考作者另外的文章:《InnoDB 行记录格式(行记录格式实验,重要).md》
  5. 在 LOCK_DATA 还出现了新的内容 supremum pseudo-record (上界限伪记录),详细内容参考作者另外的文章:《InnoDB 行记录格式(行记录格式实验,重要).md》

1.2 实验 1(续):带着问题继续实验

问题 1:为什么要锁定全部的记录呢

如果仅仅锁定 id 为 12 的记录,另外一个会话把 id 为 14 的记录改为 id 为 12,这样不就破坏了 for update 排它的语义了

问题 2:如果在别的会话中插入数据可以吗

实验步骤如下:

  1. 继续实验,另开一个会话,插入任意数据
-- 1、开启另外一个会话
begin;
-- 2、插入数据( id为12 或 id为非12 均可)
INSERT INTO `t1` ( `id` , `name` ) VALUES (20, 'ddd');
  1. 观察结果和 performance_schema.data_Lock 表中的情况

观察图中情况:

1、在别的会话中插入任何数据都会被阻塞然后超时

2、在 data_Lock 表中出现了新的 2 条记录

先对表加了一个 IX 意向排它锁,这很好理解,insert 操作必然会先对表加意向排它锁

然后对某个页中的伪记录 supremum pseudo-record 加了 X,INSERT_INTENTION 锁(具体哪一页其实在 MySQL 5.7 中可以通过表 INNODB_Lock 找到,但在 MySQL 8.0 的表 data_Lock 中不再显示),这肯定跟原本给伪记录加的 X 锁不兼容,那就肯定会等待啊

问题 3:经过上面 2 个问题,既然别的会话既不能插入也不能锁定任何记录,那为啥不直接锁定表,反而是锁定全表的记录

因为当前会话还是可以修改的,这也算是不加主键的危害了,如果是大表将导致非常多的锁记录被生成,很消耗心内存,危!!!

1.3 实验 2:有主键时如何锁定

实验步骤如下:

  1. 环境准备
-- 准备表
CREATE TABLE `t1` (
 `id` int NOT NULL,
 `name` varchar(20) DEFAULT NULL,
    PRIMARY KEY ( `id` )
);
-- 准备数据(id值不要全部连续)
INSERT INTO `t1` ( `id` , `name` ) VALUES (10, 'aaa');
INSERT INTO `t1` ( `id` , `name` ) VALUES (11, 'bbb');
INSERT INTO `t1` ( `id` , `name` ) VALUES (13, 'ccc');
INSERT INTO `t1` ( `id` , `name` ) VALUES (20, 'ddd');
  1. 开启一个客户端执行 行记录锁定
-- 1、开启一个事务
begin;
-- 2、锁定
select * from t1 where id = 11 for update;
  1. 观察 performance_schema.data_Lock 锁定的内容

观察图中情况:

1、索引名称为主键索引

2、先对表加了 IX 意向锁

3、锁定的数据是就是主键数据,而不是自动生成的 RowID

2 关于 Next-Key Lock 的实验

Record Lock:记录锁,锁定的是索引记录

Gap Lock:间隙锁,作用在索引之间的间隙上,或者第一条记录之前,或者最后一条记录之后

Next-Key Lock 是 Gap Lock 和 Record Lock 的结合

先来点理论介绍吧:

1、Next-Key Lock 是结合了 Gap Lock 和 Record Lock 的一种锁定算法,在 Next-Key Lock算法下,InnoDB 对于行的查询都是采用这种锁定算法

2、仅在查询的列是唯一索引的情况下,Next-Key Lock降级为Record Lock,即仅锁住索引本身,而不是范围

3、而对于辅助索引,其加上的是 Next-Key Lock,锁定的范围是索引的左边间隙和右边间隙至于是否包含边界看索引是升序或降序(看实验)

2.1 实验 3:如何确定算法的锁定范围

提示:本实验针对插入操作,删除修改操作在边界问题有轻微区别

实验步骤如下:

  1. 环境准备(索引 idx_b 是普通索引不是唯一索引)
-- 1、准备表
CREATE TABLE `t1` (
 `a` int NOT NULL,
 `b` int DEFAULT NULL,
  PRIMARY KEY ( `a` ),
  KEY `idx_b` ( `b` )
);
-- 2、插入记录(b字段不要连续)
insert into t1 select 1,1;
insert into t1 select 3,1;
insert into t1 select 5,3;
insert into t1 select 7,6;
insert into t1 select 10,8;
  1. 开启一个客户端执行 行记录锁定 ,并关注锁情况
begin;
select * from t1 where b = 3 for update;

观察图中情况:

一共有 2 个索引,一个是主键索引,一个是普通索引

1、对主键索引(聚簇索引),其仅仅对 a=5 的索引加上 X,REC_NOT_GAP

2、而对于辅助索引 idx_b,使用 Next-Key Lock 技术加锁

3、而对于辅助索引 idx_b,使用 Next-Key Lock 技术加锁。锁定的范围是该记录左边右边的空隙,至于是否包含某一边的边界要看索引是升序排序还是降序,对本文因为索引是升序的,所以最终的锁定范围是: (1,6) + 1 ,合并为[1,6)

  1. 另起一个会话执行如下操作,观察是否能插入成功
-- 1、另外开一个会话
begin;
-- 2、既然是间隙锁,那就有必要对 b=3 的前前后后的临界情况进行『`分别`』测试
insert into t1 select 20,0;    -- (OK)
insert into t1 select 21,1;    -- (阻塞)X,GAP,INSERT_INTENTION
insert into t1 select 22,2;    -- (阻塞)X,GAP,INSERT_INTENTION
insert into t1 select 23,3;    -- (阻塞)X,GAP,INSERT_INTENTION
insert into t1 select 24,4;    -- (阻塞)X,GAP,INSERT_INTENTION
insert into t1 select 25,5;    -- (阻塞)X,GAP,INSERT_INTENTION
insert into t1 select 26,6;    -- (OK)
insert into t1 select 27,7;    -- (OK)

分析上表的实验结果:

1、b=3 不能插入好理解,如果能插入肯定影响别的会话

2、b 在区间 (1,3)(3,6) 不能插入也好理解,因为索引 idx_b 是排序的且不是唯一索引,所以根本没有办法知道在该条记录的左边右边是否有或有几条 b=3 的数据,那么只好退而求其次锁定该记录左右的空隙,即锁定 (1,3)(3,6)

3、至于边界情况,即 1 或 6 是否应该允许插入,要根据索引是升序还是降序来确定

  • 索引升序(升序情况下,索引值小的排列在前面索引值大的排列在后面)

    如果插入 b=6 索引必然会出现在 b=6 位置后面,与现有的间隙不矛盾,所以边界 b=6 可以插入

    如果插入 b=1 索引必然会出现在 b=1 位置后面,与现有的间隙矛盾,所以边界 b=1 不可以插入

  • 索引降序(降序情况下,索引值大的排列在前面索引值小的排列在后面)

    如果插入 b=6 索引必然会出现在 b=6 位置后面,与现有的间隙矛盾,所以边界 b=6 不可以插入

    如果插入 b=1 索引必然会出现在 b=1 位置后面,与现有的间隙不矛盾,所以边界 b=1 可以插入

综上,针对插入操作,合并得到插入操作的锁定区间是: [1,6)

2.2 实验 4:降序索引下,算法的锁定范围

提示:本实验针对插入操作,删除修改操作在边界问题有轻微区别

实验步骤如下:

  1. 环境准备(注意:idx_b 索引是降序的)

    -- 1、准备表
    CREATE TABLE `t1` (
    

a int NOT NULL,
b int DEFAULT NULL,
PRIMARY KEY ( a ),
KEY idx_b ( b DESC)
);
– 2、插入记录(b字段不要连续)
insert into t1 select 1,1;
insert into t1 select 3,1;
insert into t1 select 5,3;
insert into t1 select 7,6;
insert into t1 select 10,8;


2. 开启一个客户端执行 `行记录锁定`

```mysql
begin;
select * from t1 where b = 3 for update;
  1. 另起一个会话执行如下操作,观察是否能插入成功

    -- 1、另外开一个会话
    begin;
    -- 2、既然是间隙锁,那就有必要对 b=3 的前前后后的临界情况进行『`分别`』测试
    insert into t1 select 20,0;    -- (xxx)
    insert into t1 select 21,1;    -- (xxx)
    insert into t1 select 22,2;    -- (xxx)
    insert into t1 select 23,3;    -- (xxx)
    insert into t1 select 24,4;    -- (xxx)
    insert into t1 select 25,5;    -- (xxx)
    insert into t1 select 26,6;    -- (xxx)
    insert into t1 select 27,7;    -- (xxx)
    

    后面步骤留给读者

    补充上表的结果,并得出降序索引下算法的锁定范围是什么

2.3 实验 5:幻读实验(Next-Key Lock 与 幻读)

什么是幻读:事务A读取与搜索条件相匹配的若干行,但事务B以插入或删除行等方式来影响了事务A的结果集

例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样

一般避免幻读的方法是增加范围锁RangeS,锁定检索范围为只读,这样就避免了幻读

既然 Next-Key Lock 算法锁定了记录左右的间隙,且是排它方式锁定的,是不是就意味着该间隙区间内既不能插入也不能删除或修改

实验步骤如下:

  1. 环境准备并设置隔离级别为 RR

    -- 1、准备表
    CREATE TABLE `t1` (
    

a int NOT NULL,
b int DEFAULT NULL,
PRIMARY KEY ( a ),
KEY idx_b ( b )
);
– 2、插入记录
insert into t1 select 2,1;
insert into t1 select 4,3;
insert into t1 select 6,5;
insert into t1 select 8,7;
insert into t1 select 10,9;
– 3、设置隔离级别为 RR
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
– 4、查看隔离级别
SELECT @@SESSION.transaction_isolation;


2. 开启一个客户端执行 `行记录锁定` ,并关注锁情况

```mysql
begin;
select * from t1 where b = 5 for update;
  1. 猜测实验结果

    根据实验 3 的经验来看:

    1、插入时锁定的索引范围是: [3,7) ,左闭右开,这也很好理解,插入时毕竟会插入索引嘛,但是删除或修改时是不是或许边界会有不同

    2、更新边界 b=3 预测会成功,但是如果把 b 更新为 b=5 呢,不也破坏了 for update 的语义了,所以结果不一定

    3、如果删除了 b=3 那么间隙不就变了吗,所以结果也不一定

    begin;
    delete from t1 where b = 3;             -- (预测会成功)
    update t1 set b = 5 where b = 3;        -- (预测只要不把 b 更新为 3 就会成功)
    update t1 set b = 11 where b = 3;       -- (预测只要不把 b 更新为 3 就会成功)
    update t1 set b = 12 where b = 5;       -- (预测肯定阻塞)
    rollback;
    
  2. 既然已经预测了结果,那么另起一个会话执行如下操作,观察是情况

    begin;
    delete from t1 where b = 3;             -- (OK)
    update t1 set b = 5 where b = 3;        -- (阻塞)
    update t1 set b = 11 where b = 3;       -- (OK)
    update t1 set b = 12 where b = 5;       -- (阻塞)
    rollback;
    

    😁😄,全部预测成功,good boy!

    作者看了一眼 data_locks 多了很多记录,相当复杂反正我也看不懂但是没有关系,算法很复杂但是很符合常识,根本不需要懂,嘿嘿

  3. 既然可以删除边界 b=3,但是删除后明显间隙就变了呀,Next-Key Lock 算法机制是不是也认为间隙也变了,间隙是动态的呢

    删除边界 b=3 后,新的边界变成了 b=1,那么对于插入会改变索引的操作而言是不是插入 b=1 会失败呢

    -- 1、删除 b=1 并提交
    begin;
    delete from t1 where b = 3;             -- (OK)
    commit;
    -- 2、测试边界是不是已经变成了 0,然后 0 插入失败
    begin;
    insert into t1 select 3,1;             -- (预测会阻塞)
    rollback;
    

    还是预测成功了,间隙锁的间隙是动态变化的过程

实验结果:

Next-Key Lock 算法通过锁定间隙区间避免了幻读问题,在间隙区间内不允许插入、删除、修改,对这些操作会阻塞,自然也就避免了幻读问题

3 实验总结与疑问

实验结果:

实验 1:

1、不加主键索引危害多,如果是大表哪怕随便锁定一行也会导致全表的记录被锁定,会创建大量的锁记录,很很大不良影响

2、因为没有唯一约束,所以哪怕对任意一行加行锁也会锁定所有记录,而且还不允许别的会话插入

实验 2:

1、加主键索引好处多(加行锁时只锁定一行不影响其他行)

实验 3 和实验 4:

1、一般情况的,可以理解 Next-Key Lock 算法锁定的索引范围是: (m,n) 。至于是否包含边界具体看情况,影响了锁定的间隙就不行,一般你的感觉就是准的,所以是否包含边界就不重要了

2、对算法的理解重点是对于『间隙』的理解,其实就是字面意思,一个索引范围。这个范围是动态的,如何理解,如发生了数据删除自然间隙就变大了

实验 5:

Next-Key Lock 算法通过锁定一段索引间隙区间,在区间内的操作都是排它的,区间内不允许插入、删除、修改,从而避免了幻读问题

总结:

1、实验目的在于加强对理论的理解,实验完发现一切就是那么自然根本不需要记忆

2、锁它锁定的标的是什么(猜到了吧:就是索引,具体来说就是索引中的 LOCK_DATA

3、理解 Next-Key Lock 算法的关键是对『间隙』的理解,本质上是锁定了一段索引区间,只要不干涉该索引区间的操作都是被允许的,干涉该索引区间的操作都是不被允许的

4、幻读的一般避免方案就是范围锁,锁定的范围内只允许读,从而避免了幻读

4、Next-Key Lock 算法通过锁定索引间隙,使其它客户端不可以插入、修改、删除该间隙内的内容,从而避免了幻读问题

疑问:

1、从实验 3 的结果来看,锁定的区间是: [1,6) ,但是在上图中并没有很好的体现出锁定的范围,那么应该怎么理解 LOCK_MODE 与 LOCK_DATA 呢?

2、LOCK_MODE 的 X 不像是表达『排它锁』的含义,而有点『范围锁』的味道

作者也找了一些资料,并没有很好的对 LOCK_MODE 的说明,各位看官如知道欢迎联系交流

4 参考资料

官网: https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html

官网(data_locks 表): https://dev.mysql.com/doc/refman/8.0/en/performance-schema-data-locks-table.html

书籍:《InnoDB 存储引擎》


传送门: 保姆式Spring5源码解析

欢迎与作者一起交流技术和工作生活

联系作者

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

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

相关文章

VS 字体不对齐解决方案

1. 问题描述 输入相同数量但不是同一类型的字符的字符,会出现字符显示不对齐的问题。 在某些需要根据对齐来写的代码的时候,这种情况是相当的折磨。 2. 解决方案 设置等宽字体。 依次点击 VS 上方的 工具 → 选项 → 字体和颜色 → 字体 → 随便选择一款…

基于simulink识别彩色视频序列中的交通警告标志

一、前言 此示例演示如何识别彩色视频序列中的交通警告标志,如“停止”、“请勿进入”和“让行”。 二、模型 下图显示了交通警告标志识别模型: 三、交通警告标志模板 该示例使用两组模板 - 一组用于检测,另一组用于识别。 为了节省计算…

Linux常用命令——ex命令

在线Linux命令查询工具 ex 启动vim编辑器的ex编辑模式 补充说明 在ex模式下启动vim文本编辑器。ex执行效果如同vi -E,适用于法及参数可参照vi指令,如要从Ex模式回到普通模式,则在vim中输入:vi或:visual即可。 语法 ex(参数&…

【算法设计与分析】集合相等问题——设计一个拉斯维加斯算法,对于给定的集合S和T,判定其是否相等。

目录 一、问题描述二、问题分析三、运行结果四、源代码 一、问题描述 给定两个集合S和T,试设计一个判定S和T是否相等的蒙特卡洛算法。 数据输入: 由文件input.txt给出输入数据。第1行有1个正整数n,表示集合的大小。接下来的2行,每…

路径规划算法:基于梯度优化的路径规划算法- 附代码

路径规划算法:基于梯度优化的路径规划算法- 附代码 文章目录 路径规划算法:基于梯度优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要:本文主要介绍利用智能优化算法梯度…

关于线程池其他一些知识点的讨论

文章目录 前言一、线程池的几种任务队列1.ArrayBlockingQueue2.LinkedBlockingQueue3.DelayedWorkQueue4.SynchronousQueue 二、如何确定核心线程数?三、线程池的种类有哪些?1.newFixedThreadPool2.newSingleThreadExecutor3.newCacheThreadPool4.newSch…

AI掌绘艺术:揭秘Stable Diffusion华美图韵背后那些提示词的秘密

开篇 好了好了,我知道这个标题有点大,大得像我妈的锅一样。但是,我保证,当你读完这篇文章后,你不仅会明白我为什么敢用这样的标题,而且你也会想试试宝贵的AI画画方法。 首先,我要说&#xff0…

【ARM Coresight 系列文章 3.1 - ARM Coresight DP 对 AP 的访问 1】

文章目录 1.1 DP 中相关寄存器的介绍1.1.1 DPACC and APACC 寄存器1.1.2 DP SELECT 寄存器1.1.3 AP CSW寄存器1.1.4 AP TAR 寄存器1.1.5 AP DRW寄存器1.1.6 AP Banked Data registers 1.1 DP 中相关寄存器的介绍 如果DAP接入的是JTAG接口,那么将会通过APACC寄存器来…

idea中非常好用的配置

1、自动导包和优化多余的包 2、显示行号、方法之间的分隔符 3、忽略大小写进行提示 4、多个类不隐藏,多行显示 5、鼠标悬浮代码提示 6、加入类之前的稳定注释模板 好了,文章就分享到这里了,看完之后如果对你有所帮助,不要忘了点赞…

【机器学习核心总结】什么是长短时记忆网络(LSTM)

什么是长短时记忆网络(LSTM) RNN有一定的记忆能力,但不幸的是它只能保留短期记忆,在各类任务上表现并不好,那该怎么办? 人们将目光投向了自己,人类的记忆是有取舍的,我们不会记住每时每刻发生的所有事,会…

学无止境·MySQL④(多表查询)

多表查询试题 试题一1、创建表2、表中添加数据3、查询每个部门的所属员工4、查询研发部门的所属员工5、查询研发部和销售部的所属员工6、查询每个部门的员工数,并升序排序7、查询人数大于等于3的部门,并按照人数降序排序 试题一 1、创建表 use mydb3; – 创建部门…

技术文本的写作问题

最近刚参与一位大佬的重要文本撰写,也就3000字,磨了有几个月。 收获很多。关于技术写作,要写透,要写简单;要舍得放弃。 写透看起来简单,其实是最难的。一般人看到有字数限制就拼命压缩文本,把…

从零开始制作一个Web蜜罐扫描器(1)

从零开始制作一个Web蜜罐扫描器(0)_luozhonghua2000的博客-CSDN博客 蜜罐有什么特征 根据我们上面的描述,现在可以理解,蜜罐的功能是诱捕黑客. 诱捕黑客是利用的jsonp劫持技术来做。 jsonp劫持技术需要利用jsonp跨域请求很多其他的社交网站页面从而获得攻击者的相关信息。 因…

SpringBoot第20讲:SpringBoot如何对接口进行签名

SpringBoot第20讲:SpringBoot如何对接口进行签名 在以SpringBoot开发后台API接口时,会存在哪些接口不安全的因素呢?通常如何去解决的呢?本文是SpringBoot第20讲,主要介绍API接口有不安全的因素以及常见的保证接口安全的…

青岛大学_王卓老师【数据结构与算法】Week04_12_案例分析与实现2_学习笔记

本文是个人学习笔记,素材来自青岛大学王卓老师的教学视频。 一方面用于学习记录与分享,另一方面是想让更多的人看到这么好的《数据结构与算法》的学习视频。 如有侵权,请留言作删文处理。 课程视频链接: 数据结构与算法基础–…

Python+OpenCV人行道盲道边缘侦测识别

程序示例精选 PythonOpenCV人行道盲道边缘侦测识别 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<PythonOpenCV人行道盲道边缘侦测识别>>编写代码&#xff0c;代码整洁&#x…

使用 Jest 在 Visual Studio Code 中进行更好的单元测试

目录 前言&#xff1a; 使用 Jest 扩展显著改善测试流程 1.自动启动 Jest 测试 2. 显示单个失败/通过的测试用例 允许调试单元测试 在文件中显示代码覆盖率 结论 前言&#xff1a; Jest是一个流行的JavaScript测试框架&#xff0c;它提供了简洁、灵活和强大的工具来编写…

ChatGPT炒股:查询分析某个公募基金的持仓变化

如果很认同某个基金经理的投资理念&#xff0c;可以跟踪基金经理的持仓变化&#xff0c;可以获取一些投资的线索。手动操作也可以实现&#xff0c;但略微麻烦&#xff0c;如果利用ChatGPT写一个跟踪程序&#xff0c;就方便多了。 下面以汇丰晋信副总经理、投资总监、知名基金经…

深入理解java虚拟机精华总结:线程安全与锁优化

深入理解java虚拟机精华总结&#xff1a;线程安全与锁优化 线程安全Java语言中的线程安全不可变绝对线程安全相对线程安全线程兼容线程对立 线程安全的实现方法互斥同步非阻塞同步无同步方案 锁优化自旋锁与自适应自旋锁消除锁粗化轻量级锁偏向锁 线程安全 当多个线程同时访问…

MF30:VBA_清除Excel缓存

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…