ReentrantLock与synchronized区别之比较(面试)

背景:

我们Java开发中需要保证数据线程安全时有多重选择,直接使用线程安全的集合类,或者某些变量我们通过ReentrantLock来保证安全,或者使用synchronized关键字,那两者有何区别?

备注:

ReentrantLock和synchronized关键字在服务部署多个副本时,无法在多个副本之间实现分布式锁,这时建议使用Redis或者Zookeeper提供分布式锁,其中redis使用redisson会更加便捷,并且redisson除了提供分布式锁外,还提供队列集合等

官方文档:https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

分析

1,相似点:

这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的(操作系统需要在用户态与内核态之间来回切换,代价很高,不过可以通过对锁优化进行改善)。

2,功能区别:

两种方式最大区别就是synchronized是java语言的关键字,是原生语法层面的互斥,是jvm实现的。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成

便利性:很明显,synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReentrantLock需要代码主动调用lock/unlock来加锁和释放锁,为了避免忘记异常时或者忘记释放锁,强烈建议在finally中声明释放锁。以免没有释放释放锁造成DeadLock,

 class X {private final ReentrantLock lock = new ReentrantLock();// ...public void m() {lock.lock();  // block until condition holdstry {// ... method body} finally {lock.unlock();}}}

锁的细粒度和灵活度:很明显ReentrantLock优于synchronized
Synchronized可以对方法,代码块进行同步,实现实例级别,类级别的同步
lock可以根据需要对具体需要同步的变量在改变和读取的部分进行加锁和解锁。 lock种类多,例如有ReentrantLock,ReentrantReadWriteLock。

备注:StampedLock 不是可重入的

由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:

1.等待可中断

持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。通过lock.lockInterruptibly()来实现这个机制。

2.公平锁

多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,synchronized锁是非公平锁,ReentrantLock默认的构造函数创建的也是非公平锁,可以通过将参数设置为true创建公平锁,但公平锁表现的性能不是很好。

3.锁绑定多个条件

一个ReentrantLock对象可以同时绑定多个对象。ReentrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。

创建公平/非公平锁

    /*** Creates an instance of {@code ReentrantLock} with the* given fairness policy.** @param fair {@code true} if this lock should use a fair ordering policy*/public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}

3,性能的区别:

在synchronized优化前,synchronized的性能是比ReentrantLock差很多的,但是自从synchronized引入了偏向锁、轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized。

研究发现锁在大多数情况下不存在多线程竞争情况,总是由同一个线程多次获得。在对象的mark word中进行记录,获取锁的时候先测试是否是偏向锁,

JVM会再当前线程的栈帧中创建用于存储锁记录的空间,并将对象头中的mark word复制到锁记录中,官方称为displaced mark word。 线程尝试使用cas将对象头中的mark word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示其他线程在竞争,当前线程使用自旋锁来获取锁。轻量级锁会自动升级额重量级锁,

synchronized
synchronized关键字经过编译之后,会在同步块的前后分别形成monitorenter和monitorexit两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计数器加1,相应的,在执行monitorexit指令时会将锁计数器减1,当计数器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。
monitorexit会插入到方法结束, 异常时也会释放。
synchronized是可重入的,不会出现同一个线程调用的多个方法或者代码块有synchronized自己被自己锁死的状况。

比较表 1

比较项Locksynchronized
锁的获取与释放方式必须手动管理锁的获取与释放。通常在try/finally中使用,如lock.lock()获取锁,lock.unlock()释放锁Java虚拟机自动管理锁的获取与释放。当进入syncronized修饰的方法或代码块时,自动获取锁;当退出syncronized修饰的方法或代码块或者异常时,自动释放锁。
是否可中断可中断。如果线程正在等待锁,那么可以被中断,此功能由lock.lockInterruptibly()提供。不可中断。一旦线程开始等待获取锁,并不能被中断
公平性默认非公平锁,但可配置为公平锁。如果设置为公平锁,则按照线程等待的顺序来获取锁非公平锁。它无法保证等待的线程获取锁的顺序。
其他lock可以创建Condition无其他功能

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

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

相关文章

Linux编程——多任务间通信和同步

在前面的文章中(Linux编程基础——多线程),简单对Linux中的多线程进行了介绍,包括pthread、信号量与互斥锁,本文将对Linux编程中的多任务间通信与同步技术进行相对完整的补充。 在Linux中有两种多任务实现手段&#xf…

ubuntu20.04安装MySQL8、MySQL服务管理、mysql8卸载

ubuntu20.04安装MySQL8 #更新源 sudo apt-get update #安装 sudo apt-get install mysql-serverMySQL服务管理 # 查看服务状态 sudo service mysql status # 启动服务 sudo service mysql start # 停止服务 sudo service mysql stop # 重启服务 sudo service mysql restart登…

中间件安全-CVE复现WeblogicJenkinsGlassFish漏洞复现

目录 服务攻防-中间件安全&CVE复现&Weblogic&Jenkins&GlassFish漏洞复现中间件-Weblogic安全问题漏洞复现CVE_2017_3506漏洞复现 中间件-JBoos安全问题漏洞复现CVE-2017-12149漏洞复现CVE-2017-7504漏洞复现 中间件-Jenkins安全问题漏洞复现CVE-2017-1000353漏…

idea设置字体大小快捷键 Ctrl+鼠标上下滑 字体快捷键缩放设置

双击 按住ctrl鼠标滑轮上划放大就好了 这个双击设置为,Ctrl鼠标下滑 字体缩小就好了

03-垃圾收集策略与算法

垃圾收集策略与算法 程序计数器、虚拟机栈、本地方法栈随线程而生,也随线程而灭;栈帧随着方法的开始而入栈,随着方法的结束而出栈。这几个区域的内存分配和回收都具有确定性,在这几个区域内不需要过多考虑回收的问题,因…

手把手创建属于自己的ASP.NET Croe Web API项目

第一步:创建项目的时候选择ASP.NET Croe Web API 点击下一步,然后配置: 下一步:

Adobe Photoshop 基本操作

PS快捷键 图层 选择图层 Ctrl T:可以对图层的大小和位置进行调整 填充图层 MAC: AltBackspace (前景) or CtrlBackspace (背景) WINDOWS: AltDelete (前景) or CtrlDelete (背景) 快速将图层填充为前景色或背景色 平面化图层(盖印图层&#xff09…

性能测试LoadRunner02

本篇主要讲:通过Controller设计简单的测试场景,可以简单的分析性能测试报告。 Controller 设计场景 Controller打开方式 1)通过VUG打开 2)之间双击Controller 不演示了,双击打开,选择Manual Scenario自…

《视觉 SLAM 十四讲》V2 第 9 讲 后端优化1 【扩展卡尔曼滤波器 EKF BA+非线性优化(Ceres、g2o)】

文章目录 第9讲 后端19.1.2 线性系统和 KF9.1.4 扩展卡尔曼滤波器 EKF 不足 9.2 BA 与 图优化9.2.1 投影模型和 BA 代价函数9.2.2 BA 的求解9.2.3 稀疏性 和 边缘化9.2.4 鲁棒核函数 9.3 实践: Ceres BA 【Code】本讲 CMakeLists.txt 9.4 实践:g2o 求解 …

100 # mongoose 的使用

mongoose elegant mongodb object modeling for node.js https://mongoosejs.com/ 安装 mongoose npm i mongoose基本示例 const mongoose require("mongoose");// 1、连接 mongodb let conn mongoose.createConnection("mongodb://kaimo313:kaimo313loc…

如何从小白成长为AI工程师笔记

📚入门机器学习基础 对于本科生来说,需要打好数学基础,包括高数、概率论和线性代数。 对于已经上研究生或工作想转行的人来说,可以直接开始学习机器学习算法,重要的是理解算法的原理和推导过程。如果有时间和需要&am…

Roslyn 去除多余using

原因 当你添加新代码的时候VS会自动帮你添加对应的using,但是它只会帮你加不会帮你减 由于运行时并不能使用UnityEditor命名空间里面的东西。你就算加了也会在打包的时候给你报错,除非使用宏包裹起来 因为我们打包都是在打包机上操作的。一般情况下自己…

vue3 拖拽插件 Vue3DraggableResizable

Vue3DraggableResizable 拖拽插件的官方文档 一、Vue3DraggableResizable 的属性和事件 1、Vue3DraggableResizable 的属性配置 属性类型默认值功能描述示例initWNumbernull设置初始宽度&#xff08;px&#xff09;<Vue3DraggableResizable :initW“100” />initHNumb…

sql高级教程-索引

文章目录 架构简介1.连接层2.服务层3.引擎层4.存储层 索引优化背景目的劣势分类基本语法索引结构和适用场景 性能分析MySq| Query Optimizerexplain 索引优化单表优化两表优化三表优化 索引失效原因 架构简介 1.连接层 最上层是一些客户端和连接服务&#xff0c;包含本地sock通…

1 Go的前世今生

概述 Go语言正式发布于2009年11月&#xff0c;由Google主导开发。它是一种针对多处理器系统应用程序的编程语言&#xff0c;被设计成一种系统级语言&#xff0c;具有非常强大和有用的特性。Go语言的程序速度可以与C、C相媲美&#xff0c;同时更加安全&#xff0c;支持并行进程。…

[架构之路-241]:目标系统 - 纵向分层 - 企业信息化与企业信息系统(多台企业应用单机组成的企业信息网络)

目录 前言&#xff1a; 一、什么是信息系统&#xff1a;计算机软件硬件系统 1.1 什么是信息 1.2 什么是信息系统 1.3 什么是信息技术 1.4 什么是信息化与信息化转型 1.5 什么是数字化与数字化转型&#xff08;信息化的前提&#xff09; 1.6 数字化与信息化的比较 1.7 …

力扣每日一题58:最后一个单词的长度

题目描述&#xff1a; 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 示例 1&#xff1a; 输入&#xff1a;s "Hello World&q…

Arduino IDE + Esp32 Cam + 实现视频流 + 开发环境部署

1、开发环境 Arduino ide 版本&#xff1a;2.2.1 esp32工具&#xff1a;2.0.5 示例代码 #include "esp_camera.h" #include <WiFi.h>// // WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality // Ensure ESP32 Wrover Modu…

Zookeeper、Kafka集群与Filebeat+Kafka+ELK架构、部署实例

Zookeeper、Kafka集群与FilebeatKafkaELK架构、部署实例 一、Zookeeper1.1、Zookeeper 定义1.2、Zookeeper 工作机制1.3、Zookeeper 特点1.4、Zookeeper 数据结构1.5、Zookeeper 应用场景1.5、Zookeeper 选举机制1.5.1、 第一次启动选举机制1.5.2、 非第一次启动选举机制 二、Z…

二、UI入门

1. QWidget类 QWidget类是Qt所有图形用户界面&#xff08;组件&#xff09;的基类&#xff0c;因此QWidget类内部规定了所有最基础的UI相关功能。例如以下成员&#xff1a; ● width : const int 宽度&#xff08;单位&#xff1a;像素&#xff0c;后文同&#xff09; Qt中的…