Java 并发编程面试题——重入锁 ReentrantLock

news2024/10/5 13:51:09

目录

  • 1.ReentrantLock 是什么?
  • 2.✨什么是重入锁?ReentrantLock 是如何实现可重入特征的?
  • 3.公平锁和非公平锁有什么区别?ReentrantLock 分别是如何实现的?
  • 4.✨ReentrantLock 的实现原理是什么?
  • 5.为什么 ReentrantLock 默认使用非公平锁?
  • 6.✨synchronized 和 ReentrantLock 有什么区别?
  • 7.将 ReentrantLock 放在方法内部声明会有什么问题?为什么不能放在方法里面?
  • 8.可中断锁和不可中断锁有什么区别?

在了解 ReentrantLock 之前可以先查看这篇文章 Java 并发编程面试题——Lock 与 AbstractQueuedSynchronizer (AQS)

1.ReentrantLock 是什么?

(1)ReentrantLock 实现了 Lock 接口,是一个可重入且独占式的锁,和 synchronized 关键字类似。不过,ReentrantLock 更灵活、更强大,增加了轮询、超时、中断、公平锁和非公平锁等高级功能。

public class ReentrantLock implements Lock, Serializable {
	//...
}

(2)ReentrantLock 里面有一个内部类 Sync,Sync 继承 AQS (AbstractQueuedSynchronizer),添加锁和释放锁的大部分操作实际上都是在 Sync 中实现的。Sync 有公平锁 FairSync 和非公平锁 NonfairSync 两个子类。

在这里插入图片描述

(3)ReentrantLock 默认使用非公平锁,也可以通过构造器来显示的指定使用公平锁。

// fair 为 true 时为公平锁,false 时为非公平锁
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权利再次获取这把锁。如果是不可重入锁,那么第二次获得锁时,自己也会被锁挡住。

2.✨什么是重入锁?ReentrantLock 是如何实现可重入特征的?

(1)重入锁是指支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁,ReentrantLock 本身就是重入锁。重入锁具备重入特性,即允许同一个线程多次获取锁,而不会导致线程死锁。这使得编程更加灵活,可避免一些潜在的问题。

(2)可重入是指任意线程在获取到锁之后能够再次获取该锁而不会被锁所阻塞,该特性的实现需要解决以下两个问题:

  • 线程再次获取锁:锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取。
  • 锁的最终释放:线程重复 n 次获取了锁,随后在第 n 次释放该锁后,其他线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于 0 时表示锁已经成功释放。

(3)ReentrantLock 是通过组合自定义同步器来实现锁的获取与释放,以非公平性(默认的)实现为例,其处理逻辑如下:

  • 线程再次获取锁:通过判断当前线程是否为获取锁的线程来决定获取操作是否成功,如果是获取锁的线程再次请求,则将同步状态值 state 进行加一操作并返回 true,表示获取同步状态成功;
  • 锁的最终释放:成功获取锁的线程再次获取锁,只是增加了同步状态值,这也就要求 ReentrantLock 在释放同步状态时减少同步状态值。如果该锁被获取了 n 次,那么前 (n - 1) 次 tryRelease(int releases) 方法必须返回 false,而只有同步状态完全释放了,才能返回true。可以看到,该方法将同步状态是否为 0 作为最终释放的条件,当同步状态为 0 时,将占有线程设置为 null,并返回 true,表示释放成功;

思考:为什么需要可重入锁?
回答:在多线程编程中,可能会出现线程需要在多个方法中嵌套使用同一把锁的情况。如果没有可重入锁的支持,那么一个线程在持有锁的情况下再次请求这个锁时,就会发生自己阻塞的情况,导致出现死锁。可重入锁的出现则解决了这个问题,它允许线程多次获取同一把锁,确保在未释放锁之前,线程仍然可以正常地访问该锁所保护的资源。

3.公平锁和非公平锁有什么区别?ReentrantLock 分别是如何实现的?

(1)公平锁和非公平锁之间的区别如下:

  • 公平锁 : 锁被释放之后,会严格按照请求线程的顺序来分配锁,即先到先得。性能较差一些,因为公平锁为了保证时间上的绝对顺序,上下文切换更频繁。
  • 非公平锁:锁被释放之后,允许线程通过插队来抢占锁资源,即后申请的线程可能会先获取到锁,是随机或者按照其他优先级排序的。性能更好,但可能会导致某些线程永远无法获取到锁。

(2)ReentrantLock 默认使用非公平锁,其内部使用了 AQS 来实现锁资源的竞争,没有竞争到锁资源的线程会加入到 AQS 的同步队列中,该同步队列是由一个双向链表实现的:

  • ReentrantLock 实现公平锁的方式是线程在竞争锁资源时会判断同步队列中有没有等待线程,如果有就加入到同步队列的尾部进行等待;
  • 非公平锁的实现方式是不管同步队列里面有没有线程等待,它都会先去尝试抢占锁资源,如果抢占不到,才会加入到同步队列的尾部进行等待。

4.✨ReentrantLock 的实现原理是什么?

ReentrantLock 实现了 Lock 接口,是一个可重入且独占式的锁,ReentrantLock 的底层实现有以下几个非常重要的方面:

  • 锁的竞争
    • ReentrantLock 有一个非常重要的内部类 Sync,Sync 继承 AQS,添加锁和释放锁的大部分操作实际上都是在 Sync 中实现的。
    • AQS 采用了一个 int 类型的互斥变量 state 用来记录锁竞争的一个状态,0 表示当前没有任何线程竞争锁资源,而大于等于 1 表示已经有线程正在持有锁资源。一个线程来获取锁资源的时候,首先判断 state 是否等于 0,如果是(无锁状态),则把这个 state 更新成 1,表示占用到锁。此时如果多个线程进行同样的操作,会造成线程安全问题。AQS 采用了 CAS 机制来保证 state 的原子性。
    • 对于没有竞争到锁的线程,它们会被存储到 AQS 的同步队列中,该同步队列的底层是通过双向链表来实现的。当锁被释放之后,会从 AQS 队列里面的头部唤醒下一个等待锁的线程。具体过程如下图所示:
      在这里插入图片描述
  • 锁的可重入:可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权利再次获取这把锁,其余具体实现过程见上面的分析;
  • 锁的公平性和非公平性:Sync 有公平锁 FairSync 和非公平锁 NonfairSync 两个子类,其余具体实现过程见上面的分析;

5.为什么 ReentrantLock 默认使用非公平锁?

(1)ReentrantLock 默认使用非公平锁是为了优化性能。非公平锁在获取锁时不会考虑等待队列中其他线程的顺序,而是允许新到来的线程插队获取锁,这在某些情况下可以减少线程切换的开销,提高整体的吞吐量

(2)而公平锁则会遵循先进先出的原则,保证所有线程按照请求的顺序获取锁,这会增加线程切换的开销,但可以避免饥饿的发生。由于大多数情况下公平性不是一个强制要求,因此非公平锁被认为是默认的更合理选择。不过,如果有特定的需求,ReentrantLock 也提供了可以配置的公平锁选项。

6.✨synchronized 和 ReentrantLock 有什么区别?

(1)synchronized 和 ReentrantLock 都是用于实现线程同步的机制,它们的主要区别在于以下几个方面:

  • 本质:synchronized 是⼀个关键字,ReentrantLock 是⼀个
  • 加锁方式:synchronized 会自动的加锁与释放锁,ReentrantLock 则需要通过 lock() 方法与 unlock() 方法手动加锁与释放锁;
  • 公平性:ReentrantLock 默认情况是非公平的,但可以通过 ReentrantLock 类的 ReentrantLock(boolean fair) 构造方法来制定是否是公平的;而 synchronized 只能是非公平锁,即无法保证等待时间最长的线程先获得锁。
  • 锁性质:synchronized 是 JVM 层面的锁;ReentrantLock 是 API 层面的锁;
  • 中断支持:ReentrantLock 提供了可以响应中断的获取锁的方式,而 synchronized 没有中断的语义。
  • 等待可中断:ReentrantLock 提供了一个 tryLock(long time, TimeUnit unit) 方法,该方法可以尝试获取锁一段时间,在指定时间内获取不到锁会返回 false,从而避免了线程一直阻塞的情况。
  • 锁状态保存:synchronized 锁的是对象,锁信息保存在对象头中;ReentrantLock 通过代码中 int 类型的 state 变量来标识锁的状态;
  • 条件变量:ReentrantLock 可以配合 Condition 接口实现更灵活的线程通信和同步。
  • 性能:在高并发情况下,ReentrantLock 通常比 synchronized 性能更好。

(2)综上所述,虽然 synchronized 简单易用,但是在一些复杂的场景下可能无法满足需求,此时可以使用 ReentrantLock 来实现更灵活的线程同步。但需要注意的是,由于 ReentrantLock 比 synchronized 更加复杂,使用不当可能会导致死锁等问题,因此在使用 ReentrantLock 时需要格外小心。

相关知识点:
Java 并发编程面试题——synchronized 与 volatile
Java 并发编程面试题——Condition 接口

7.将 ReentrantLock 放在方法内部声明会有什么问题?为什么不能放在方法里面?

(1)ReentrantLock 是 Java 提供的一个可重入锁实现,用于在多线程环境中提供更灵活的同步控制。通常情况下,应该将 ReentrantLock 的声明放在类的成员变量位置,而不是放在方法内部。如果将 ReentrantLock 放在方法内部声明,会导致以下问题:

  • 互斥性失效:每次方法调用都会创建一个新的 ReentrantLock 对象,这意味着每个线程都会获取到一个独立的锁。因此,无法实现多个线程之间的互斥访问,即使是同一个线程多次调用同一个方法,也无法保证其互斥性。
  • 数据共享困难:将 ReentrantLock 放在方法内部,会导致每个线程拥有自己的锁对象。这会造成在线程间共享数据时的困扰,因为多个线程无法共享同一个锁对象来保护共享数据的访问。如果不同的线程持有不同的锁对象,那么锁的语义将失效,无法保证数据的一致性和正确性。
  • 锁无法释放:当将 ReentrantLock 放在方法内部声明时,每个线程都会创建一个独立的锁对象,并在其方法执行完毕后释放锁。这意味着即使其他线程仍然需要访问该方法所保护的共享资源,它们无法获取到被锁保护的权限,从而造成了资源的长时间阻塞和不必要的等待。

(2)综上所述,不推荐将 ReentrantLock 放在方法内部声明。相反,应该将 ReentrantLock 的声明放在类的成员变量位置,使得所有线程都共享同一个锁对象,并确保互斥性、数据一致性和正确的资源释放

8.可中断锁和不可中断锁有什么区别?

  • 可中断锁 :获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。ReentrantLock 就属于是可中断锁。
  • 不可中断锁 :一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。 synchronized 就属于是不可中断的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1191894.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文了解Nginx及其基本配置

一、关于Nginx Nginx是一个开源的高性能HTTP和反向代理服务器。 Nginx可以用于处理静态资源、负载均衡、反向代理和缓存等任务。 Nginx被广泛用于构建高可用性、高性能的Web应用程序和网站。 Nginx具有低内存消耗、高并发能力和良好的稳定性,因此在互联网领域非常受…

易点易动固定资产管理系统:实现全生命周期闭环式管理和快速盘点

固定资产管理对于企业来说至关重要,它涉及到资产的采购、领用、使用、维护和报废等各个环节。然而,传统的固定资产管理方式往往繁琐、耗时,容易导致信息不准确和资源浪费。为了解决这些问题,我们引入易点易动固定资产管理系统&…

酷开科技智能大屏OS Coolita亮相第134届中国进出口商品交易会

作为中国外贸的“风向标”和“晴雨表”,广交会因其历史长、规模大、商品种类全、到会客商多、成交效果好,被称为“中国第一展”,它见证了中国改革开放的时代大潮与对外贸易的蓬勃发展。 2023年10月15日,第134届中国进出口商品交易…

《012.SpringBoot+vue之在线考试系统》【前后端分离有开发文档】

《012.SpringBootvue之在线考试系统》【前后端分离&有开发文档】 项目简介 [1]本系统涉及到的技术主要如下: 推荐环境配置:idea jdk1.8 maven MySQL 前后端分离; 后台:SpringBootMybatisMySQL; 前台:Vue; [2]功能模块展示&…

泛微E-Mobile 6.0命令执行漏洞

声明 本文仅用于技术交流,请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。 一、漏洞原理 泛微E-Mobile 6.0存在命令执行漏洞的问题,在…

B087-人力资源项目-文件上传课程分类

目录 背景控制台操作开通OSS服务创建存储空间 项目工程准备概述新建文件管理模块把文件上传到OSS的三种方案 通过官方文档完成demo上传官方文档找JavaSDK文件上传思路代码 背景 为什么要交给第三方文件管理服务管理? 最传统的的文件管理方案是把文件存储到项目中本…

ADS错误Error警告warning记录持续更新

ADS错误Error警告warning记录持续更新 简介环境1 (smithdg.ael line 7843, column 12 in multiply) Value or parameter is NULL 简介 由于ADS的报错不是很好能找到问题源头,因此记录我在仿真遇到的错误与警告,和其解决办法。 环境 ADS2020 1 (smith…

TCP和UPD协议

一)应用层协议简介:根据需求明确要传输的信息,明确要传输的数据格式; 应用层协议:这个协议,实际上是和程序员打交道最多的协议了 1)其它四层都是操作系统,驱动,硬件实现好了的,咱们是不需要管 2)应用层:当我…

嵌入式软件开发常用工具有哪些?

分享一些嵌入式软件开发常用工具。 1、Keil MDK:这是德国Keil公司开发的基于8051、9051、ARM7、ARM9系列微控制器的嵌入式软件开发工具,它提供了包括C编译器、宏汇编、连接器、库管理器、仿真器等在内的完整开发方案。Keil还提供了丰富的中间件和库函数&…

AntDB-M高性能设计之hash索引动态rehash

AntDB-M支持hash索引、btree索引等索引类型,hash索引以hash表的方式实现,一个简单的hash表示意图如图1所示。hash桶下的元素节点为单向或者双向链表,数据行上某一个或者某几个字段组成索引,通过hash函数对索引字段的值进行运算&am…

【计网 传输层概述】 中科大郑烇老师笔记 (十)

目录 0 引言1 概述1.1 传输服务和协议1.2 传输层 vs 网络层1.3 Internet传输层协议 TCP和UDP 2 多路复用、解复用2.1 UDP的多路复用2.2 TCP的多路复用 3 UDP3.1 概述3.2 UDP报文段3.3 拓展:TCP报文段 🙋‍♂️ 作者:海码007📜 专栏…

浅谈安科瑞直流电表在加拿大光伏系统中的应用

摘要:本文介绍了安科瑞直流电表DJSF1352在加拿大光伏系统中的应用。主要用于光伏系统中的电流的计量,配合分流器对电流进行计量。 Abstract: This article introduces the application of Acrel DC meters in PV system in Canada.The device is measu…

css:clip元素裁剪实现Loading加载效果边框

clip 属性定义了元素的哪一部分是可见的。clip 属性只适用于 position:absolute 的元素。 警告: 这个属性已被废弃。建议使用 clip-path 文档 https://developer.mozilla.org/zh-CN/docs/Web/CSS/cliphttps://developer.mozilla.org/zh-CN/docs/Web/CSS/clip-path …

振南技术干货集:C语言的一些“骚操作”及其深层理解(2)

注解目录 第二章《c语言的一些“操作”及其深层理解》 一、字符串的实质就是指针 (如何将 35 转为对应的十六进制字符串”0X23”?) 二 、转义符\ (打入字符串内部的“奸细”。) 三、字符串常量的连接 &#xff…

2023年【公路水运工程施工企业安全生产管理人员】复审考试及公路水运工程施工企业安全生产管理人员考试试题

题库来源:安全生产模拟考试一点通公众号小程序 公路水运工程施工企业安全生产管理人员复审考试根据新公路水运工程施工企业安全生产管理人员考试大纲要求,安全生产模拟考试一点通将公路水运工程施工企业安全生产管理人员模拟考试试题进行汇编&#xff0…

asp.net学生部门管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net 学生部门管理系统是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使用c#语言 开发 asp.net学生部门管理系统1 应用技…

详解机器学习最优化算法

前言 对于几乎所有机器学习算法,无论是有监督学习、无监督学习,还是强化学习,最后一般都归结为求解最优化问题。因此,最优化方法在机器学习算法的推导与实现中占据中心地位。在这篇文章中,小编将对机器学习中所使用的…

Springboot通过ObjectMapper(节点树)解析JSON

1、ObjectMapper通过节点树的方式解析JSON字符串 1.1、通过节点直接获取属性值 1.1.1、测试代码 node.get("order_id"):直接获取JSON中属性对应的值 Test public void parseJson() throws Exception{//创建json字符串,模拟从外界接收的订…

2023年【危险化学品生产单位安全生产管理人员】最新解析及危险化学品生产单位安全生产管理人员理论考试

题库来源:安全生产模拟考试一点通公众号小程序 危险化学品生产单位安全生产管理人员最新解析考前必练!安全生产模拟考试一点通每个月更新危险化学品生产单位安全生产管理人员理论考试题目及答案!多做几遍,其实通过危险化学品生产…

halcon分割粘连字符

下面的算子都可以分割: 1.*(推荐使用这个)在垂直范围较小的位置水平划分区域 partition_dynamic(circleRegion,parRegion,76,50)2.*将一个区域划分为大小大致相等的矩形。(这个方法适合宽度相等,很规则的排列的字符串…