常见的锁策略
乐观锁vs悲观锁
乐观:
预测锁冲突的概率不高,因此做的工作就可以简单一点
悲观:
预测锁冲突(两个线程竞争同一把锁,产生锁冲突,会阻塞等待)的概率较高,因此做的工作就要复杂一些
读写锁 VS 普通互斥锁
普通的互斥锁,就如同synchronized
当两个线程竞争同一把锁,就会产生等待
读写锁,分成两种情况
- 加读锁
- 加写锁
读锁和读锁之间,不会产生竞争~
写锁和写锁之间,有竞争~ ~
读锁和写锁之间,有竞争~ ~
读的场景往往很多,写的场景往往更少
读写锁相比于普通的互斥锁,就少了很多的锁竞争,优化了效率!
重量级锁 VS 轻量级锁
也是一个锁策略~
轻量级锁,加锁解锁开销比较小
重量级锁,加锁开锁解锁开销比较大
典型的,纯用户态的加锁逻辑,开销是比较小
典型的,进入内核态的加锁逻辑,开销是比较大的
重量级锁和轻量级锁是 : 站在结果的角度看待的,最终加锁解锁操作消耗的时间是多还是少
- 乐观锁,指的是干的事情少
- 悲观锁,指的是干的事情多
乐观锁和悲观锁是 : 站在加锁的过程中看的,加锁解锁过程中干的工作是多还是少
因此通常情况下,乐观锁,一般也比较轻量,悲观锁,一般比较重量(干的工作多,消耗的时间就多)
但是也不绝对~ ~
上述锁策略,指的都是实现锁的时候考虑的
自旋锁和挂起等待锁
自旋锁是轻量级锁的一种典型实现(更及时,需要的时间更短,所以是轻量级锁)
挂起等待锁,是重量级锁的一种典型实现(获取锁消耗的时间更长,并且中途会做别的事,做的事更多,所以是重量级锁)
自旋就类似于 “忙等” ,消耗大量的CPU,反复询问当前的锁是否就绪~
自旋锁是纯用户态实现的,和进入内核相比的工作量还是要更少~
两种等待策略:
- 自旋(一直请求获取锁)
- 挂起等待
挂起等待的时候,获取到的锁时间就更久(没那么及时了),但是这个时间里,CPU可以干别的!
公平锁 VS 非公平锁
公平锁:
遵守 “先来后到”. t1,t2,t3竞争同一把锁,谁先来的,谁就先拿到锁~
非公平锁:
不遵循"先来后到",t1,t2,t3都有可能拿到锁
操作系统默认的锁的调度,是非公平的情况~ |
要想实现公平锁,需要引入额外的数据结构,来记录线程加锁的顺序,需要一定的额外开销
可重入锁VS 不可重入锁
- 可重入锁 : 同一个线程针对同一把锁,连续加锁两次,不会死锁!
- 不可重入锁 : 同一个线程针对同一把锁,连续加锁两次,会死锁!