30. 技术专题-锁
文章目录
- 前言
- 一、通用
- 一、Java
- 1. 轻量级锁
- 2. 重量级锁
- 3. 自旋锁
- 4. 偏向锁
- 二、数据库
- 1. 悲观锁
- 2. 乐观锁
- 3. 行锁
- 4. 页锁
- 5. 表锁
- 6. 共享锁/读锁
- 7. 排他锁/写锁
- 8. 间隙锁
- 9. 分布式锁
前言
锁
。
一、通用
锁的类型,从宏观上分类,分为悲观锁与乐观锁。
- 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。
java中的乐观锁基本都是通过CAS操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。
- 悲观锁
悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如RetreenLock。
一、Java
java的4种锁,他们分别是重量级锁、自旋锁、轻量级锁和偏向锁。
不同的锁有不同特点,每种锁只有在其特定的场景下,才会有出色的表现,java中没有哪种锁能够在所有情况下都能有出色的效率,引入这么多锁的原因就是为了应对不同的情况;
重量级锁是悲观锁的一种,自旋锁、轻量级锁与偏向锁属于乐观锁,所以现在你就能够大致理解了他们的适用范围,但是具体如何使用这几种锁呢,就要看后面的具体分析他们的特性;
1. 轻量级锁
2. 重量级锁
3. 自旋锁
4. 偏向锁
二、数据库
1. 悲观锁
数据库被外界(包括本系统当前的其他事物以及来自外部系统的事务处理)修改保持着保守态度,因此在整个数据修改过程中,将数据处于锁状态。悲观的实现往往是依靠数据库提供的锁机制,也只有数据库层面提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统汇总实现了加锁机制,也是没有办法保证系统不会修改数据。
在悲观锁的情况下,为了保证事务的隔离性,就需要一致性锁定。读取数据时给加锁,其它事务无法修改这些数据。修改删除数据时也要加锁,其它事务无法读取这些数据。
2. 乐观锁
相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。
悲观锁为保证操作最大程度的独占性,带来了数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。
而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实现。
何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
3. 行锁
行级锁是一种排他锁,防止其他事务修改此行。
容易出现死锁,发生冲突概率低,并发高,InnoDB 支持行锁(MySQL 行锁只能加在索引上,如果操作不走索引,就会升级为表锁。行锁是加在索引上的,如果不走索引,就没法使用行锁了)。
4. 页锁
页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。
表级锁速度快,但冲突多,行级冲突少,但速度慢。
所以取了折衷的页级,一次锁定相邻的一组记录。BDB支持页级锁。
5. 表锁
对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。系统开销最小,会锁定整张表,MyISAM 使用表锁。表级锁,分为表共享读锁(共享锁)与表独占写锁(排他锁)。
6. 共享锁/读锁
表共享读锁。
不堵塞,多个用户可以同一时刻读取同一个资源,相互之间没有影响。
7. 排他锁/写锁
表独占写锁。
一个写操作阻塞其他的读锁和写锁,这样可以只允许一个用户进行写入,防止其他用户读取正在写入的资源。
8. 间隙锁
9. 分布式锁
基于Redis
-
获取锁的时候,使用setnx加锁,锁的value 值为一个随机生成的UUID,在释放锁的时候进行判断。并使用expire命令为锁添加一个超时时间,超过该时间则自动释放锁。(SETNX keyval:当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0)
-
获取锁的时候调用setnx,如果返回0,则该锁正在被别人使用,返回1则成功获取锁。还设置一个获取的超时时间,若超过这个时间则放弃获取锁。
-
释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行锁释放。