[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 ...
随机推荐
- Windows 命令行切换目录
Windows 命令行切换目录 特别注意:切换到其它盘符不需要 cd 命令 1. 切换到 C 盘根目录 打开终端 cmd 后,输入cd C:\(一定要加上后面的反斜扛) 2.切换到 C 盘子目录 打开 ...
- git合并分支理解和常用命令的总结
原文参考:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 工作区和暂存区 工作区 ...
- 长安大学第四届ACM-ICPC“迎新杯”程序设计竞赛-重现赛 G - 彩虹岛套娃
题目描述 俄罗斯套娃是俄罗斯特产的木制玩具,一般由多个一样图案的空心木娃娃一个套一个组成,最多可达十多个,通常为圆柱形,底部平坦可以直立.颜色有红色,蓝色,绿色,紫色等.最普通的图案是一个穿着俄罗斯民 ...
- TensorFlow——module 'tensorflow' has no attribute 'xxx'
tf.sub()更改为tf.subtract() tf.mul()更改为tf.multiply() tf.types.float32更改为tf.float32 tf.pact()更改为tf.stact ...
- Windows 消息循环(1) - 概览
本文从消息循环是如何驱动程序的这个角度,对 Windows 消息循环进行概览性介绍. 使用 EN5 课件获得更好的阅读体验: [希沃白板5]课件分享 : <Windows培训 - 消息循环> ...
- GeneXus项目启动
使用GeneXus产品开发项目时,在开始,有一些属性我会经常改一下.我现在使用的GeneXus版本是GeneXus U3,由于在做手机应用的开发,所以一般使用最新的版本,老外那边差不多两个月会有一个u ...
- linux——(7)了解shell
概念一:什么是shell 用户用来和内核交互的东西,他相当一个接口,我们通过这个接口调用别的程序,然后他调用内核来帮我们完成程序功能.shell有很多种类,他们之间有部分区别,Linux默认使用bas ...
- Eclipse酷炫项目、最新趋势介绍
作为Eclipse基金组织的执行董事,我需要经常审阅每一个新提交的Eclipse项目协议书.作为Eclipse的一分子,我很乐意与加入我们团队的新开发人员互动.这也是我工作中的乐趣之一.2013年,我 ...
- prim 算法和 kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...
- poj 1659 Frogs' Neighborhood( 青蛙的邻居)
Frogs' Neighborhood Time Limit: 5000MS Memory Limit: 10000K Total Submissions: 9639 Accepted: 40 ...