乐观锁和悲观锁
1基本区别
名称 |
核心点 |
说明 |
场景 |
悲观锁(pessimistic lock) |
操作之前加锁 (最坏情况) |
每次拿数据时都认为别人会修改,因此每次拿数据时都上锁 注意点: Mysql innodb中使用悲观锁一定要关闭自动提交属性(默认autocommit模式,即执行一个更新操作后,mysql会立刻将结果提交。)需要设置autocommit=0 |
写多高并发 关系型数据库行锁,表锁,读写锁等。 Java中synchronized和ReentrantLock等独占锁 |
乐观锁(opitmistic lock) |
操作之前不加锁 (最好情况) |
每次拿数据时认为别人不会修改,因此不上锁,更新时判断下数据有没有被更新 |
读多低并发。 版本号和cas方式实现。 数据库提供的类似于write_condition机制。 java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的 |
2乐观锁实现方式
1)版本号
update table set x=x+1, version=version+1 where id=#{id} and version=#{version};
2)cas方式
Compare and swap(比较与交换),无锁情况下实现多线程间变量同步。即非阻塞同步(non-blocking synchronization)
实现操作数:
需要读写的内存值V,进行比较的值A,拟写入的新值B。
当且仅当V值等于A时,CAS通过原子方式用新值B更新V的值,否则不会执行任何操作(比较和替换是一个原子操作),一般情况下是一个自旋操作(即不断重试)
https://blog.csdn.net/hongchangfirst/article/details/26004335
https://blog.csdn.net/liaohaojian/article/details/62416972
https://blog.csdn.net/L_BestCoder/article/details/79298417
https://blog.csdn.net/qq_34337272/article/details/81072874
2.1乐观锁缺点
问题 |
说明 |
解决方法 |
ABA问题 |
如果一个变量V初次读取时是A值,且在准备赋值时检查到仍然是A值,不能确定没有被其他线程修改过。因为可能被修改为其他值,然后又改回A值。即cas操作会误认为从来没有被修改过,即ABA问题。 |
Jdk1.5后的AtomicStampedReference 类提供了compareAndSet。即先检查当前引用是否等于预期引用,并当前标志是否等于预期标志,如果全等,则以原子方式将该引用和标志值设置为给定的更新值。 |
循环时间长开销大 |
自旋CAS即不成功就一直循环执行直到成功,如果长时间不成功会增加cpu开销。 |
|
2.2补充说明
CAS和synchronized使用场景:
|
说明 |
其他 |
CAS |
低并发情况下,使用synchronized同步锁进行线程阻塞和唤醒切换额外浪费cpu资源。而cas基于硬件实现,不需要进入内核,切换线程,操作自旋几率少,性能更高 |
注意:cas实现方式是使用cpu层面的命令保证原子性,硬件级别的! |
synchronized |
高并发情况下,线程冲突严重,cas自旋几率大,浪费过多cpu资源,效率低于synchronized |
Jdk1.6后对synchronized进行了优化 |
https://blog.csdn.net/qq_34337272/article/details/81072874
3悲观锁
共享锁和排它锁是悲观锁的不同实现,一般数据库已实现,可直接调用。
3.1Mysql中共享锁,排他锁,悲观锁,乐观锁
3.1.1 innodb与myisam
引擎 |
说明 |
其他 |
innodb |
与myisam最大不同点 1)innodb支持事务 2)Innodb采用行锁 注意:行锁不是直接锁记录,而是锁索引。 如果sql操作了主键索引则锁主键索引,操作非主键索引则先锁该非主键索引,再锁主键索引。如果没有索引或不通过索引条件检索数据,那么innodb将锁表。 |
Mysql5.5之后使用innodb |
myisam |
Myisam操作数据使用表锁,性能低 |
Mysql5.5之前默认使用myisam存储引擎 |
3.1.2 mysql中锁
注意:数据库增删改操作默认都会加排他锁,而查询不会加任何锁。
数据库规定:同一资源上不能同时加共享锁和排他锁。
类别 |
说明 |
场景 |
共享锁 |
对某一资源加共享锁,自身和其他人都可以读该资源,但无法修改。必须等所有共享锁释放完才能修改 (读锁) 多个不同事务对同一个资源共享同一个锁。(相当于一个门有多个钥匙) |
select * from myemployeee where id=322051 lock in share mode |
排他锁 |
对某一资源加排他锁,自身可进行增删改查,其他人无法进行任何操作 (写锁) |
select * from myemployeee where id=322051 for update |
https://blog.csdn.net/puhaiyang/article/details/72284702
https://blog.csdn.net/localhost01/article/details/78720727
对mysql中的锁描述的还是不太清楚,后续再进行理解。