[Todo] 乐观悲观锁,自旋互斥锁等等
乐观锁、悲观锁、要实践
http://chenzhou123520.iteye.com/blog/1860954 《mysql悲观锁总结和实践》
http://chenzhou123520.iteye.com/blog/1863407 《mysql乐观锁总结和实践》
http://outofmemory.cn/sql/optimistic-lock-and-pessimistic-lock
注意,以下的表里面的列名,一定要用 `` 反引号来包括。
mysql> create table `t_goods` (
-> `id` bigint(11) NOT NULL AUTO_INCREMENT,
-> `status` bigint(11) DEFAULT 0,
-> `name` varchar(32) DEFAULT NULL,
-> `version` bigint(11) DEFAULT 1,
-> PRIMARY KEY (`id`)
-> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.13 sec)
mysql> insert into t_goods (`name`) values ('weapon');
Query OK, 1 row affected (0.07 sec)
mysql> insert into t_goods (`name`) values ('equipment');
Query OK, 1 row affected (0.10 sec)
mysql> select * from t_goods;
+----+--------+-----------+---------+
| id | status | name | version |
+----+--------+-----------+---------+
| 1 | 0 | weapon | 1 |
| 2 | 0 | equipment | 1 |
+----+--------+-----------+---------+
2 rows in set (0.00 sec)
实验1,select for update 指定主键,只锁行:
首先要关闭autocommit:
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec) mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | OFF |
+---------------+-------+
1 row in set (0.00 sec)
如果不关闭,经过实验,的确不会相互影响。
关闭autocommit之后,普通的sql不放在事务里面也可以。
console A: mysql> select * from t_goods where id = 1 for update;
+----+--------+--------+---------+
| id | status | name | version |
+----+--------+--------+---------+
| 1 | 0 | weapon | 1 |
+----+--------+--------+---------+
1 row in set (0.00 sec) console B:
mysql> select * from t_goods where id = 1;
+----+--------+--------+---------+
| id | status | name | version |
+----+--------+--------+---------+
| 1 | 0 | weapon | 1 |
+----+--------+--------+---------+
1 row in set (0.00 sec) mysql> select * from t_goods where id = 2 for update;
+----+--------+-----------+---------+
| id | status | name | version |
+----+--------+-----------+---------+
| 2 | 0 | equipment | 1 |
+----+--------+-----------+---------+
1 row in set (0.00 sec) mysql> select * from t_goods where id = 1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
可以看出,不加for update不影响,加了for update不是同一行,不影响(仅对于主键查询有关)。
实验2,select for update 指定非主键,锁全部:
Console A:
mysql> select * from t_goods where name = 'weapon' for update;
+----+--------+--------+---------+
| id | status | name | version |
+----+--------+--------+---------+
| 1 | 0 | weapon | 1 |
+----+--------+--------+---------+
1 row in set (0.00 sec) Console B:
mysql> select * from t_goods;
+----+--------+-----------+---------+
| id | status | name | version |
+----+--------+-----------+---------+
| 1 | 0 | weapon | 1 |
| 2 | 0 | equipment | 1 |
+----+--------+-----------+---------+
2 rows in set (0.00 sec) mysql> select * from t_goods where name = 'equipment' for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> select * from t_goods where id = 2 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
实验3,查询主键没查到,不锁:
Console A:
mysql> select * from t_goods where id=3 for update;
Empty set (0.01 sec) Console B:
mysql> select * from t_goods for update;
+----+--------+-----------+---------+
| id | status | name | version |
+----+--------+-----------+---------+
| 1 | 0 | weapon | 1 |
| 2 | 0 | equipment | 1 |
+----+--------+-----------+---------+
2 rows in set (0.00 sec)
说明,主键没查到数据,不加锁。
实验4,查询非主键,没查到,锁全部,table lock.
Console A:
mysql> select * from t_goods where name = 'abc' for update;
Empty set (0.00 sec) Console B:
mysql> select * from t_goods for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction mysql> select * from t_goods where id = 1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
实验5:查询主键不明确,为范围,大于小于,只锁相关的行;
Console A:
mysql> select * from t_goods where id > 1 for update;
+----+--------+-----------+---------+
| id | status | name | version |
+----+--------+-----------+---------+
| 2 | 0 | equipment | 1 |
+----+--------+-----------+---------+
1 row in set (0.00 sec) Console B:
mysql> select * from t_goods where id = 1 for update;
+----+--------+--------+---------+
| id | status | name | version |
+----+--------+--------+---------+
| 1 | 0 | weapon | 1 |
+----+--------+--------+---------+
1 row in set (0.00 sec) mysql> select * from t_goods where id = 2 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
实验5:查询主键不明确,!=或者<>,锁全部;
Console A:
mysql> select * from t_goods where id != 1 for update;
+----+--------+-----------+---------+
| id | status | name | version |
+----+--------+-----------+---------+
| 2 | 0 | equipment | 1 |
+----+--------+-----------+---------+
1 row in set (0.00 sec) Console B:
mysql> select * from t_goods where id = 1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction Console A:
mysql> select * from t_goods where id <> 1 for update;
+----+--------+-----------+---------+
| id | status | name | version |
+----+--------+-----------+---------+
| 2 | 0 | equipment | 1 |
+----+--------+-----------+---------+
1 row in set (0.00 sec) Console B:
mysql> select * from t_goods where id = 1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
实验6,对于普通索引,也类似于主键的效果:
未加索引之前,锁全表:
console A:
mysql> select * from t_goods where status = 1 for update;
+----+--------+--------+---------+
| id | status | name | version |
+----+--------+--------+---------+
| 1 | 1 | weapon | 1 |
+----+--------+--------+---------+
1 row in set (0.00 sec) console B:
mysql> select * from t_goods where id = 2 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 加了索引之后,只锁行:
console A:
mysql> alter table t_goods add index index_name(`status`);
Query OK, 0 rows affected (0.15 sec)
Records: 0 Duplicates: 0 Warnings: 0 mysql> select * from t_goods where status = 1 for update;
+----+--------+--------+---------+
| id | status | name | version |
+----+--------+--------+---------+
| 1 | 1 | weapon | 1 |
+----+--------+--------+---------+
1 row in set (0.00 sec) console B:
mysql> select * from t_goods where id = 2 for update;
+----+--------+-----------+---------+
| id | status | name | version |
+----+--------+-----------+---------+
| 2 | 0 | equipment | 1 |
+----+--------+-----------+---------+
1 row in set (0.00 sec) mysql> select * from t_goods where id = 1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
乐观锁:
从业务层面加锁,一般是加上version字段,然后sql以如下形式处理:
update t_goods
set status=2,version=version+1
where id=#{id} and version=#{version};
自旋锁与互斥锁
http://blog.csdn.net/a675311/article/details/49096435
自旋锁就是不听的忙检测,拿不到锁就返回。
pthread中提供的锁有:pthread_mutex_t, pthread_spinlock_t, pthread_rwlock_t。 pthread_mutex_t是互斥锁,同一瞬间只能有一个线程能够获取锁,其他线程在等待获取锁的时候会进入休眠状态。因此pthread_mutex_t消耗的CPU资源很小,但是性能不高,因为会引起线程切换。
pthread_spinlock_t是自旋锁,同一瞬间也只能有一个线程能够获取锁,不同的是,其他线程在等待获取锁的过程中并不进入睡眠状态,而是在CPU上进入“自旋”等待。自旋锁的性能很高,但是只适合对很小的代码段加锁(或短期持有的锁),自旋锁对CPU的占用相对较高。
pthread_rwlock_t是读写锁,同时可以有多个线程获得读锁,同时只允许有一个线程获得写锁。其他线程在等待锁的时候同样会进入睡眠。读写锁在互斥锁的基础上,允许多个线程“读”,在某些场景下能提高性能。
诸如pthread中的pthread_cond_t, pthread_barrier_t, semaphone等,更像是一种同步原语,不属于单纯的锁。
http://www.cnblogs.com/hdflzh/p/3716156.html
http://blog.csdn.net/pi9nc/article/details/39177343
Java锁相关
http://blog.csdn.net/Evankaka/article/details/44153709 (这一篇要重点看,讲了Thread Runnable等)
http://blog.csdn.net/Evankaka/article/details/51866242(Java锁技术内幕上)
http://blog.csdn.net/evankaka/article/details/51932044(Java锁技术内幕中)
[Todo] 乐观悲观锁,自旋互斥锁等等的更多相关文章
- Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等
Java 中15种锁的介绍 Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等,在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类 ...
- C# lock 语法糖实现原理--《.NET Core 底层入门》之自旋锁,互斥锁,混合锁,读写锁
在多线程环境中,多个线程可能会同时访问同一个资源,为了避免访问发生冲突,可以根据访问的复杂程度采取不同的措施 原子操作适用于简单的单个操作,无锁算法适用于相对简单的一连串操作,而线程锁适用于复杂的一连 ...
- C# lock的语法糖原理--《.net core 底层入门》之自旋锁,互斥锁,混合锁,读写锁
在多线程环境中,多个线程可能会同时访问同一个资源,为了避免访问发生冲突,可以根据访问的复杂程度采取不同的措施 原子操作适用于简单的单个操作,无锁算法适用于相对简单的一连串操作,而线程锁适用于复杂的一连 ...
- Java 种15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁等等…
Java 中15种锁的介绍 1,在读很多并发文章中,会提及各种各样的锁,如公平锁,乐观锁,下面是对各种锁的总结归纳: 公平锁/非公平锁 可重入锁/不可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲 ...
- 【python】-- GIL锁、线程锁(互斥锁)、递归锁(RLock)
GIL锁 计算机有4核,代表着同一时间,可以干4个任务.如果单核cpu的话,我启动10个线程,我看上去也是并发的,因为是执行了上下文的切换,让看上去是并发的.但是单核永远肯定时串行的,它肯定是串行的, ...
- 举例讲解Python中的死锁、可重入锁和互斥锁
举例讲解Python中的死锁.可重入锁和互斥锁 一.死锁 简单来说,死锁是一个资源被多次调用,而多次调用方都未能释放该资源就会造成死锁,这里结合例子说明下两种常见的死锁情况. 1.迭代死锁 该情况是一 ...
- Java中的锁-悲观锁、乐观锁,公平锁、非公平锁,互斥锁、读写锁
总览图 如果文中内容有错误,欢迎指出,谢谢. 悲观锁.乐观锁 悲观锁.乐观锁使用场景是针对数据库操作来说的,是一种锁机制. 悲观锁(Pessimistic Lock):顾名思义,就是很悲观,每次去拿数 ...
- linux自旋锁、互斥锁、信号量
为了避免并发,防止竞争.内核提供了一组同步方法来提供对共享数据的保护. 我们的重点不是介绍这些方法的详细用法,而是强调为什么使用这些方法和它们之间的差别. Linux 使用的同步机制可以说从2.0到2 ...
- GIL全局解释器锁+GIL全局解释器锁vs互斥锁+定时器+线程queue+进程池与线程池(同步与异步)
以多线程为例写个互斥锁 from threading import Thread ,Lockimport timemutex = Lock() n = 100 def task(): global n ...
随机推荐
- python开发学习-day05(正则深入、冒泡排序算法、自定义模块、常用标准模块)
s12-20160130-day05 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...
- 【51nod】2026 Gcd and Lcm
题解 话说LOJ说我今天宜学数论= =看到小迪学了杜教筛去蹭了一波小迪做的题 标解的杜教筛的函数不懂啊,怎么推的毫无思路= = 所以写了个复杂度稍微高一点的?? 首先,我们发现f是个积性函数,那么我们 ...
- Redis实战配置(三)
程序配置 我们安装好了Redis的系统服务,此时Redis服务已经运行. 现在我们需要让我们的程序能正确读取到Redis服务地址等一系列的配置信息,首先,需要在Web.config文件中添加如下信息: ...
- oracle 内连接、外连接、自然连接、交叉连接练习
oracle 内连接.外连接.自然连接.交叉连接练习 --查询员工信息 select * from emp; --查询部门信息 select * from dept; --需求:查询员工姓名.薪资和所 ...
- es6的Map()构造函数
普通的object对象是键值对的集合,但对于它的键却有着严苛的要求,必须是字符串,这给我们平时带来很多的不方便 Map函数类似于对象,但它是一个更加完美的简直对集合,键可以是任意类型 set()方法可 ...
- EOJ 3262 黑心啤酒厂
最大公约数. 计算$x$与$i$的最小公倍数,就是这些人至少需要喝几杯,最小公倍数除以$x$就是要买几瓶. #include <cstdio> #include <cmath> ...
- 折半搜索【p4799】[CEOI2015 Day2]世界冰球锦标赛
Description 今年的世界冰球锦标赛在捷克举行.Bobek 已经抵达布拉格,他不是任何团队的粉丝,也没有时间观念.他只是单纯的想去看几场比赛.如果他有足够的钱,他会去看所有的比赛.不幸的是,他 ...
- cogs——2478. [HZOI 2016]简单的最近公共祖先
2478. [HZOI 2016]简单的最近公共祖先 ★☆ 输入文件:easy_LCA.in 输出文件:easy_LCA.out 简单对比时间限制:2 s 内存限制:128 MB [题 ...
- 分割视图控制器(UISplitViewController)
这种控制器只能用于iPad,它可以在iPad屏幕中显示两个不同的场景:在横向模式下,左边显示一个表,供用户选择:用户选择表中的元素后,详细视图将显示该元素的详细信息.如果iPad被旋转到纵向模式,表将 ...
- NOIP2017 D2T3列队
这题我改了三天,考场上部分分暴力拿了50,考完试发现与正解很接近只是没写出来. 对于每一行和最后一列建n+1颗线段树,维护前缀和. 复杂度qlogn 假如你移动一个坐标为(x,y)的人,你要将第x行线 ...