1.常见的锁策略
1.1乐观锁与悲观锁
乐观锁与悲观锁是从处理锁冲突的态度方面来进行考量分类的。
- 乐观锁预期锁冲突的概率很低,所以做的准备工作更少,付出更少,效率较高。
- 悲观锁预期锁冲突的概率很高,所以做的准备工作更多,付出更多,效率较低。
- 小伙伴们有兴趣想了解内容和更多相关学习资料的请点赞收藏+评论转发+关注我,后面会有很多干货。我有一些面试题、架构、设计类资料可以说是程序员面试必备!所有资料都整理到网盘了,需要的话欢迎下载!私信我回复【111】即可免费获取
1.2读写锁与普通互斥锁
对于普通的互斥锁只有两个操作:
- 加锁
- 解锁
而对于读写锁来说有三个操作:
- 加读锁,如果代码仅进行读操作,就加读锁。
- 加写锁,如果代码含有写操作,就加写锁。
- 解锁。
针对读锁与读锁之间,是没有互斥关系的,因为多线程中同时读一个变量是线程安全的,针对读锁与写锁之间以及写锁与写锁之间,是存在互斥关系的。
在java中有读写锁的标准类,位于
java.util.concurrent.locks.ReentrantReadWriteLock,其中ReentrantReadWriteLock.ReadLock为读锁,ReentrantReadWriteLock.WriteLock为写锁。
1.3重量级锁与轻量级锁
这两种类型的锁与悲观锁乐观锁有一定的重叠,重量级锁做的事情更多,开销更大,轻量级锁做的事情较少,开销也就较少,在大部分情况下,可以将重量级锁视为悲观锁,轻量级锁视为乐观锁。
如果锁的底层是基于内核态实现的(比如调用了操作系统提供的mutex接口)此时一般认为是重量级锁,如果是纯用户态实现的,一般认为是轻量级锁。
1.4挂起等待锁与自旋锁
挂起等待锁表示当获取锁失败之后,对应的线程就要在内核中挂起等待(放弃CPU,进入等待队列),需要在锁被释放之后由操作系统唤醒,该类型的锁是重量级锁的典型实现。 自旋锁表示在获取锁失败后,不会立刻放弃CPU,而是快速频繁的再次询问锁的持有状态一旦锁被释放了,就能立刻获取到锁,该类型的锁是轻量级锁的典型实现。
挂起等待锁与自旋锁的区别
- 最明显的区别就是,挂起等待锁开销比自旋锁要大,且挂起等待锁效率不如自旋锁。
- 挂起等待锁会放弃CPU资源,自旋锁不会放弃CPU资源,会一直等到锁释放为止。
- 自旋锁相较于挂起等待锁更能及时获取到刚释放的锁。
- 自旋锁相较于挂起等待锁的劣势就是当自旋的时间长了,会持续地销耗CPU资源,因此自旋锁也可以说是乐观锁。
1.5公平锁与非公平锁
公平锁遵循先来后到的原则,多个线程在等待一把锁的时候,谁先来尝试拿锁,那这把锁就是谁的。 非公平锁遵循随机的原则,多个线程正在等待一把锁时,当锁释放时,每个线程获取到这把锁的概率是均等的。
1.6可重入锁与不可重入锁
一个线程连续加锁两次,不会造成死锁,那么这个锁就是可重入锁。 反之,一个线程连续加锁两次,会造成死锁现象,那么这个锁就是不可重入锁。
关于死锁是什么