专栏首页从流域到海域Java面试高频面试题汇总 锁专题

Java面试高频面试题汇总 锁专题

可重入锁(递归锁)

广义上可重入锁,也叫做递归锁,指的是同一线程,外层函数获得锁之后,内层函数仍有获得该锁的代码,但不受影响。Java的ReentrantLock和synchronized都是可重入锁。

公平锁和非公平锁

公平锁(Fair) 加锁前检查是否有排队等待的线程,优先排队等待的线程,先到先得。

非公平锁(Nonfair) 加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待。

  1. 非公平锁性能比公平锁高5~10倍,因为公平锁需要在多核的情况下维护一个队列。
  2. Java中的synchronized是非公平锁,ReentrantLock默认的lock方法采用的是非公平锁。

ReadWriteLock 读写锁

为了提高性能,Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制。如果没有写锁的情况下,读是无阻塞的,在一定程度上提供了程序的执行效率。

读写锁分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由JVM控制的,你只需要上好相应的锁就可以了。

读锁:如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁。 写锁:如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。

Java读写锁有对应的接口java.concurrent.locks.ReadWriteLock,也有具体的实现ReentrantReadWriteLock

共享锁和独占锁

java并发包提供的加锁模式分为共享锁和独占锁。 独占锁 独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock就是以独占方式实现的互斥锁。独占锁是一种悲观保守的加锁策略,它避免了读/读冲突,如果某个只读线程获取锁,则其他读线程都只能等待,这种情况下就限制了不必要的并发性,因为读操作并不会影响数据的一致性。

共享锁 共享锁允许多个线程同时获取锁,并访问共享资源如:ReadWriteLock。共享锁则是一种乐观锁,它放宽了加锁策略,允许多个执行读操作的线程同时访问共享资源。

  1. AQS的内部类Node定义了两个常量SHARED和EXCLUSIVE,他们分别表示AQS队列中等待线程的锁获取模式。
  2. java的并发包提供了ReadWriteLock,读-写锁。它允许一个资源可以被多个读操作访问。

重量级锁(Mutex lock,英文直译互斥锁)

Synchronized是通过对象内部的一个叫做监视器(monitor)锁来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock。而操作系统实现线程之间的切换就需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对较长的时间,这就是为什么Synchronized效率低的原因。因此,这种依赖于操作系统Mutex Lock所实现的锁称之为重量级锁。JDK中对Synchronized做的中中优化,其核心都是为了减少这种重量级锁的使用。JDK1.6之后。为来减少获得锁和释放锁带来的性能消耗,引入了“轻量级锁”和“偏向锁”。

轻量级锁

锁的状态一种有四种:无锁状态、偏向锁、轻量级锁和重量级锁。 随着锁的竞争,锁可以从偏向锁升到轻量级锁,再升级到重量级锁(锁的升级是单向的,只能从低到高,不会降级)。

“轻量级”是相对于操作系统互斥量实现传统锁而言的。但是,首先需要强调一点的是,轻量级锁并不是用来代替重量级锁的,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用产生的性能消耗。 轻量级锁所适用的场景是线程交替执行同步块的情况,如果存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀为重量级锁。

偏向锁

Hotspot的作者经过以往的研究发现大多数情况下锁不仅不存在多线程竞争,而且总是由同一线程多次获得。

偏向锁的目的是在某个线程获得锁之后,消除这个线程锁重入(CAS)的开销,看起来让这个线程得到了偏护。

引入偏向锁是为了在无多线程竞争的情况下尽量减少不必要的轻量级锁执行路径,因为轻量级锁的获取及释放依赖多次CAS原子指令,而偏向锁只需要在置换ThreadID的时候依赖一次CAS原子指令(由于一旦出现多线程竞争的情况就必须撤销偏向锁,所以偏向锁的撤销操作的性能损耗必须小于节省下来的CAS原子指令的性能消耗)。

轻量级锁是为了在线程交替执行同步块时提高性能,而偏向锁则是在只有一个线程执行同步块时进一步提高性能。

分段锁

ConcurrentHashMap,JDK7即之前实现同步的一种方式,对整个数组分段加锁,不是一种实际的锁。

锁优化

  • 减少锁持有时间 只在有线程安全要求的程序上加锁
  • 减小锁粒度 将大对象(指这个对象可能会被多线程访问)拆成小对象,大大增加并行度,降低锁竞争,降低了锁的竞争,偏向锁,轻量级锁成功率才会提高。最最典型的减小锁粒度的案例就是ConcurrentHashMap。
  • 锁分离 最常见的锁分离就是读写锁 ReadWriteLock,根据功能进行分离成读锁和写锁,这样读读不互斥,读写互斥,写写互斥,即保证了线程安全,又提高了性能。
  • 锁粗化 通常情况下,为了保证多线程间的有效并发,会要求每个线程持有锁的时间尽量短,即在使用完公共资源之后,应该立即释放锁。但是,如果对同一个锁不停的进行请求、同步和释放,其本身也会消耗系统宝贵的资源,反而不利于与性能的优化。锁粗化具体方法是将多个锁请求合并为一个。
  • 锁消除 锁消除是在编译器级别的事情。在即时编译器时,如果发现不可能被共享的对象,则可以消除这些对象的锁操作,多数是因为程序员代码不规范引起的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java面试高频问题汇总 线程池专题

    线程池提供了一种限制和管理资源(包括执行一个任务)。每个线程池还维护一些基本统计信息,例如已完成的任务数量。

    Steve Wang
  • CNNs and Deep Q Learning

    前面的一篇博文介绍了函数价值近似,是以简单的线性函数来做的,这篇博文介绍使用深度神经网络来做函数近似,也就是Deep RL。这篇博文前半部分介绍DNN、CNN...

    Steve Wang
  • 面试Java基础问题汇总 part2

    Synchronized关键字同步语句块使用的是monitorenter和monitorexit指令,其中monitorenter指令指向同步代码块的开始位置,...

    Steve Wang
  • 算法训练 删除数组零元素

    从键盘读入n个整数放入数组中,编写函数CompactIntegers,删除数组中所有值为0的元素,其后元素向数组首端移动。注意,CompactIntegers函...

    AI那点小事
  • Vcenter 无法使用已授权的域账号登陆的解决

    在Vmware vcenter中,为域账号vmadmin添加管理员权限,并将权限传播到子对象。尝试使用 vSphere Client 或 vSphere Web...

    孙杰
  • Java 虚拟机的内存结构

    我们都知道虚拟机的内存划分了多个区域,并不是一张大饼。那么为什么要划分为多块区域呢,直接搞一块区域,所有用到内存的地方都往这块区域里扔不就行了,岂不痛快。

    李鹏
  • 谷歌大脑提出:基于NAS的目标检测模型NAS-FPN,超越Mask R-CNN

    谷歌大脑的Quoc Le团队,用神经网络架构搜索 (NAS) ,发现了一个目标检测模型。长这样:

    朱晓霞
  • 超越Mask-RCNN:谷歌大脑的AI,自己写了个目标检测AI

    谷歌大脑的Quoc Le团队,用神经网络架构搜索 (NAS) ,发现了一个目标检测模型。长这样:

    磐创AI
  • Top分析/编程/ML工具,大家pick了谁? | KDnuggets2018调查

    这一次参与调查的人数超过了2300,比2017年少了一丢丢。这有可能是因为只有RapidMiner把这次调查放心上了,主动搞了一次campaign鼓励大家投票。...

    量子位
  • 1113. 括号匹配

    题目描述 给定一个只包含左右括号的合法括号序列,按右括号从左到右的顺序输出每一对配对的括号出现的位置(括号序列以0开始编号)。 输入 仅一行,表示一个合法的括号...

    attack

扫码关注云+社区

领取腾讯云代金券