又是一个小细节:面试常考的十种锁策略与synchronized涉及锁策略

锁策略主要是用于实现锁的,那么有哪些锁经常在面试中出现呢?

1.乐观锁&悲观锁

乐观锁:

即操作系统认为你所加锁的那块代码,基本上不会发生锁冲突,所以每次运行都不会加锁,当出现锁冲突(线程安全问题)时,返回错误信息让代码编写者来处理。一般处理方法是增加一个版本号或者修改时间(都是只增不减),然后每次修改数据时,先寄存器A获取版本号,给版本号+1,寄存器B再获取数据和修改数据。想要填回内存时,比较我们寄存器A的版本号是否大于旧版本号,否则不能把寄存器B的值填回内存。
在这里插入图片描述

悲观锁:

与乐观锁恰恰相反,即每次运行都会加锁
在这里插入图片描述

synchronized优化:一开始是乐观锁,当出现多次返回错误信息(锁冲突频繁)的情况上,优化成悲观锁。
在这里插入图片描述

读写锁

首先明确我们为什么会加锁,加锁是为了线程安全,那么线程安全由从何而来?主要还是数据的修改引发的,对于读数据来说是没有线程安全问题的,这样我们就可以分为下面三种情况:(以两个线程为例)
1.两个线程都读数据,线程安全
2.一读一修改数据,线程不安全
3.两个都修改数据,线程不安全
既然第一种情况是线程安全等待,那么就不必对第一种情况加锁,以节省加锁带来的资源消耗,那么读写锁就是把读操作和写操作分别进行加锁
我们java对读写锁也有专门的类,即ReentrantReadWriteLock类,感兴趣可以去了解一下。

synchronized不是读写锁

轻量级锁&重量级锁

对于这两个锁,我们要先了解锁的核心特征:原子性,这种特性本质上是基于cpu这种硬件提供的。

这里是引用

轻量级锁:尽量不依赖mutex互斥锁,能用java层面完成加锁就在java层面加锁
好处:减少用户态到内核态转变,资源消耗低,不容易引发线程调度(线程不容易挂起等待)
坏处:能处理的情况少
重量级锁:重度依赖OS(操作系统)提供的mutex互斥锁
好处:能处理的情况多
坏处:用户态到内核态频繁,消耗资源大,容易引发线程调度(线程挂起等待)

synchronized:初始是轻量级锁,情况无法处理时转为重量级锁。

自旋锁

我们直到一般出现锁冲突是,没获取到锁资源的线程都会挂起等待,这一等待下一次唤醒就不知道是什么时候了,如果我们想让某个线程时刻准备着(即每隔一会会都去尝试获取锁)要怎么做呢?自旋锁因此而来:

这里是引用
优点:线程处于时刻想获取锁的状态,锁一旦释放能第一时间获取锁
缺点:时刻的询问,会一直消耗CPU资源(挂起等待不会消耗cpu资源)

公平锁&非公平锁

公平锁:

顾名思义,讲究的就是一个公平:
在这里插入图片描述
也就是获取锁的时候,讲究线程的先来后到,先来的线程先获取锁。

非公平锁

不遵循先来后到:
在这里插入图片描述
synchronized是非公平锁

可重入锁&不可重入锁

可重入锁

就是一把锁可以被一个线程多次获取,伪代码如下

synchronized(lock){
	synchronized(lock){
		synchronized(lock){
			//do somethings
		}
	}
}//大致就是获取第一把锁后,之后相同的锁,会自动获取。

不可重入锁

与可重入恰恰相反,一把锁不可以被一个线程多次获取。如果是不可重入锁,上述伪代码就会出现死锁,把自己卡死。

// 第一次加锁, 加锁成功
lock();
// 第二次加锁, 锁已经被占用, 阻塞等待.
lock()unlock();
unlock();

synchronized是可重入锁

相关面试题:

  1. 你是怎么理解乐观锁和悲观锁的,具体怎么实现呢?
  2. 介绍下读写锁?
  3. 什么是自旋锁,为什么要使用自旋锁策略呢,缺点是什么?
  4. synchronized 是可重入锁么?

相信大家读完上述文章,应该对这些问题有了头绪
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值