锁概述:java和mysql

锁分类 : 互斥锁、自旋锁、读写锁、乐观锁、悲观锁

互斥锁: 操作系统层面的重量级锁、会带来上下文切换的开销、锁的数量有限;如果加锁失败,操作系统会将线程阻塞

自旋锁: CAS(Compare And Swap) 、会一直循环去加锁、但是如果一直获取不到锁、cpu开销会很大;

  • 互斥锁加锁失败后,线程会释放 CPU ,给其他线程;
  • 自旋锁加锁失败后,线程会忙等待,直到它拿到锁;

 

读写锁:读共享和写独占

当没有写操作时、多线程已经并发读取、提高读的性能;一旦有写操作,读和写操作都会阻塞、防止共享资源的不一致问题;

在此基础上还有读优先和写优先、不过只适合特定的场景

 

乐观锁和悲观锁

乐观锁:先修改完共享资源,再验证这段时间内有没有发生冲突,如果没有其他线程在修改资源,那么操作完成,如果发现有其他线程已经修改过这个资源,就放弃本次操作。

放弃后如何重试,这跟业务场景息息相关,虽然重试的成本很高,但是冲突的概率足够低的话,还是可以接受的。

悲观锁:多线程同时修改共享资源的概率比较高,于是很容易出现冲突,所以访问共享资源前,先要上锁

应用场景

常见的 SVN 和 Git (以及在线编辑文档)也是用了乐观锁的思想,先让用户编辑代码,然后提交的时候,通过版本号来判断是否产生了冲突,发生了冲突的地方,需要我们自己修改后,再重新提交。

乐观锁虽然去除了加锁解锁的操作,但是一旦发生冲突,重试的成本非常高,所以只有在冲突概率非常低,且加锁成本非常高的场景时,才考虑使用乐观锁。

 

Java锁:Synchronized和Lock

Synchronized是java的关键字,用来做并发控制: 字节码层面 monitorenter moniterexit

jdk1.6以后的优化 、Synchronized使用锁的变化过程 :偏向锁(无锁)  --->自旋锁(cas)---->互斥锁      

单个线程竞争,打个标签就行  偏向锁;多线程竞争,开始用cas去竞争;cas到达一定次数、使用操作系统互斥量(重量级锁、无法撤销

可以看到Synchronized适合竞争不那么激烈的并发场景下;

 

java的java.util.concurrent.locks包,包含lock相关的实现类、可重入锁、读写锁、公平锁/非公平锁

底层使用cas和AQS来实现以及操作系统的阻塞方法,通过cas和AQS提供灵活操作的java层API;

没有重量级锁,但是也没有Synchronized的自动加锁自动撤销,所以相对适合并发激烈的情况下,灵活的使用API会提高并发的性能。

 

Mysql锁:表锁、行锁、间隙锁

我觉得mysql的锁本质上锁分段、这个概念在java中也有。

ConcurrentHashMap 在jdk1.7中讲数组分为16段、不同段使用不同锁。

在JDK1.8中将ConcurrentHashMap通过同步关键字Synchronized锁链表或者红黑树。

本质上和Mysql的表级锁和行级锁非常像。

表锁:实现简单、不会出现死锁,发生锁冲突几率高,并发低。

行锁:实现复杂、会出现死锁,发生锁冲突几率低,并发高。  注意Mysql的innoDB才支持行级锁

 

Mysql涉及到插入和查询、也有读写锁以及读写意向锁

Mysql的间隙锁(Next-Key) : 锁住一行记录和下一行记录的间隙 ,例如 [1,2} [1,5}

行级锁的实现通过索引实现,索引间也是通过行级锁实现、如果没有索引按照我测试的结果、会去找主键索引、如果范围太多可能会锁表。

 

参考

https://blog.csdn.net/qq_34827674/article/details/108608566    互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景

https://www.cnblogs.com/ljl150/p/12514198.html    synchronized实现原理及其优化-(自旋锁,偏向锁,轻量锁,重量锁)

 

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页