synchronized和ReentrantLock的5个区别!

8b5a38a5d3fff243922582492614f262.png

作者 | 磊哥

来源 | Java面试真题解析(ID:aimianshi666)

转载请联系授权(微信ID:GG_Stone)

在 Java 中,常用的锁有两种:synchronized(内置锁)和 ReentrantLock(可重入锁),二者的功效都是相同得,但又有很多不同点,所以我们今天就来聊聊。

区别1:用法不同

synchronized 可用来修饰普通方法、静态方法和代码块,而 ReentrantLock 只能用在代码块上。

synchronized 基础使用

使用 synchronized 修饰代码块:

public void method() {// 加锁代码synchronized (this) {// ...}
}

ReentrantLock 基础使用

ReentrantLock 在使用之前需要先创建 ReentrantLock 对象,然后使用 lock 方法进行加锁,使用完之后再调用 unlock 方法释放锁,具体使用如下:

public class LockExample {// 创建锁对象private final ReentrantLock lock = new ReentrantLock();public void method() {// 加锁操作lock.lock();try {// ...} finally {// 释放锁lock.unlock();}}
}

区别2:获取锁和释放锁方式不同

synchronized 会自动加锁和释放锁,当进入 synchronized 修饰的代码块之后会自动加锁,当离开 synchronized 的代码段之后会自动释放锁,如下图所示:2df2e017f2da25f58b073ccbf05b11bd.png而 ReentrantLock 需要手动加锁和释放锁,如下图所示:f840e0cea34e80c5edc6e5d7490e0a4a.png

PS:在使用 ReentrantLock 时要特别小心,unlock 释放锁的操作一定要放在 finally 中,否者有可能会出现锁一直被占用,从而导致其他线程一直阻塞的问题。

区别3:锁类型不同

synchronized 属于非公平锁,而 ReentrantLock 既可以是公平锁也可以是非公平锁。默认情况下 ReentrantLock 为非公平锁,这点查看源码可知:48dacaebe436110b9217135ff10ab0a6.png使用 new ReentrantLock(true) 可以创建公平锁,查看源码可知:04f0f9a4a86d3feae43f48d32609e13f.png

区别4:响应中断不同

ReentrantLock 可以使用 lockInterruptibly 获取锁并响应中断指令,而 synchronized 不能响应中断,也就是如果发生了死锁,使用 synchronized 会一直等待下去,而使用 ReentrantLock 可以响应中断并释放锁,从而解决死锁的问题,比如以下 ReentrantLock 响应中断的示例:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockInterrupt {static Lock lockA = new ReentrantLock();static Lock lockB = new ReentrantLock();public static void main(String[] args) throws InterruptedException {// 线程 1:先获取 lockA 再获取 lockBThread t1 = new Thread(() -> {try {// 先获取 LockAlockA.lockInterruptibly();// 休眠 10 毫秒TimeUnit.MILLISECONDS.sleep(100);// 获取 LockBlockB.lockInterruptibly();} catch (InterruptedException e) {System.out.println("响应中断指令");} finally {// 释放锁lockA.unlock();lockB.unlock();System.out.println("线程 1 执行完成。");}});// 线程 2:先获取 lockB 再获取 lockAThread t2 = new Thread(() -> {try {// 先获取 LockBlockB.lockInterruptibly();// 休眠 10 毫秒TimeUnit.MILLISECONDS.sleep(100);// 获取 LockAlockA.lockInterruptibly();} catch (InterruptedException e) {System.out.println("响应中断指令");} finally {// 释放锁lockB.unlock();lockA.unlock();System.out.println("线程 2 执行完成。");}});t1.start();t2.start();TimeUnit.SECONDS.sleep(1);// 线程1:执行中断t1.interrupt();}
}

以上程序的执行结果如下所示:04b592e004921d2d2ec607c91443a6ba.png

区别5:底层实现不同

synchronized 是 JVM 层面通过监视器(Monitor)实现的,而 ReentrantLock 是通过 AQS(AbstractQueuedSynchronizer)程序级别的 API 实现。synchronized 通过监视器实现,可通过观察编译后的字节码得出结论,如下图所示:396896a1bb1ae2d4b26e99bcb7f1f7b0.png其中 monitorenter 表示进入监视器,相当于加锁操作,而 monitorexit 表示退出监视器,相当于释放锁的操作。ReentrantLock 是通过 AQS 实现,可通过观察 ReentrantLock 的源码得出结论,核心实现源码如下:112936f19984e66bd9c7cb13fc4b8e8f.png

小结

synchronized 和 ReentrantLock 都是 Java 中提供的可重入锁,二者的主要区别有以下 5 个:

  1. 用法不同:synchronized 可以用来修饰普通方法、静态方法和代码块,而 ReentrantLock 只能用于代码块。

  2. 获取锁和释放锁的机制不同:synchronized 是自动加锁和释放锁的,而 ReentrantLock 需要手动加锁和释放锁。

  3. 锁类型不同:synchronized 是非公平锁,而 ReentrantLock 默认为非公平锁,也可以手动指定为公平锁。

  4. 响应中断不同:ReentrantLock 可以响应中断,解决死锁的问题,而 synchronized 不能响应中断。

  5. 底层实现不同:synchronized 是 JVM 层面通过监视器实现的,而 ReentrantLock 是基于 AQS 实现的。

是非审之于己,毁誉听之于人,得失安之于数。

公众号:Java面试真题解析

面试合集:https://gitee.com/mydb/interview

7c5b29756a041b0a7b3d26fef08b30b5.gif

往期推荐

a692eda9a06d8c633c07e5b577938073.png

每周汇总 | Java面试题(共41篇)2022版


1166813e57754a4c72ab515f91a480ab.png

面试突击41:notify是随机唤醒吗?


fb807510cd595333e2b0481a148b79d2.png

面试突击40:线程休眠的方法有几种?


b2cc59e70ba1a04b73fb5b64c4802609.gif

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

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

相关文章

Java Random nextInt()方法与示例

随机类nextInt()方法 (Random Class nextInt() method) Syntax: 句法: public int nextInt();public int nextInt(int num);nextInt() method is available in java.util package. nextInt()方法在java.util包中可用。 nextInt() method is used to return the nex…

《小强升职记》读后感和思维导图

语言幽默轻松,寓教于乐,看完之后有挽起袖子大干一场的冲动,但是诚如书中所言,“不做收藏家,要做建筑工”,实践和坚持才能有所收获。第一次画思维导图(′▽〃)Xmind格式文件转载于:https://www.cnblogs.com/…

oppo后端16连问

前言 大家好,我是磊哥。最近有位读者去面试了oppo,给大家整理了面试真题的答案。希望对大家有帮助哈,一起学习,一起进步。聊聊你印象最深刻的项目,或者做了什么优化。你项目提到分布式锁,你们是怎么使用分布…

java enummap_Java EnumMap values()方法与示例

java enummapEnumMap类values()方法 (EnumMap Class values() method) values() method is available in java.util package. values()方法在java.util包中可用。 values() method is used to get all the values in a Collection view of this enum map. values()方法用于获取…

django 1.8 官方文档翻译:2-1-1 模型语法

模型 模型是你的数据的唯一的、权威的信息源。它包含你所储存数据的必要字段和行为。通常,每个模型对应数据库中唯一的一张表。 基础: 每个模型都是django.db.models.Model 的一个Python 子类。模型的每个属性都表示数据库中的一个字段。Django 提供一套…

实战!阿里神器 Seata 实现 TCC 模式解决分布式事务

今天这篇文章介绍一下Seata如何实现TCC事务模式,文章目录如下:目录什么是TCC模式?TCC(Try Confirm Cancel)方案是一种应用层面侵入业务的两阶段提交。是目前最火的一种柔性事务方案,其核心思想是&#xff1…

Java Dictionary get()方法与示例

字典类的get()方法 (Dictionary Class get() method) get() method is available in java.util package. get()方法在java.util包中可用。 get() method is used to get the value on the specified key element (key_ele) in this dictionary. get()方法用于获取此字典中指定键…

[CareerCup] 8.10 Implement a Hash Table 实现一个哈希表

8.10 Design and implement a hash table which uses chaining (linked lists) to handle collisions. 这道题让我们实现一个简单的哈希表,我们采用了最简单的那种取余映射的方式来实现,我们使用Cell来保存一对对的key和value的映射关系,然后…

Spring Boot 中实现跨域的 5 种方式,你一定要知道!

一、为什么会出现跨域问题出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略…

stl:queue 源码_C ++ STL中的queue :: empty()和queue :: size()

stl:queue 源码In C STL, Queue is a type of container that follows FIFO (First-in-First-out) elements arrangement i.e. the elements which inserts first will be removed first. In queue, elements are inserted at one end known as "back" and are delet…

术中导航_密码术中的计数器(CTR)模式

术中导航The Counter Mode or CTR is a simple counter based block cipher implementation in cryptography. Each or every time a counter initiated value is encrypted and given as input to XOR with plaintext or original text which results in ciphertext block. Th…

Android社交类APP动态详情代码实现通用模板

Android社交类APP动态详情代码实现通用模板 Android平台上一些比较流行的社交类APP比如微信、陌陌等,都有动态详情页,在该页面,用户发表的动态详情,好友可以发起评论、点赞等等。这种设计在微信和陌陌上大…

聊聊并发编程的12种业务场景

前言并发编程是一项非常重要的技术,无论在面试,还是工作中出现的频率非常高。并发编程说白了就是多线程编程,但多线程一定比单线程效率更高?答:不一定,要看具体业务场景。毕竟如果使用了多线程,…

软件工程编码阶段_软件工程的编码阶段

软件工程编码阶段The coding phase in the software engineering paradigm is usually defined after the designing phase. In this phase, the developers or the coders have to implement the software design practically using any computer language(s) so that the sof…

梳理50道经典计算机网络面试题

我梳理了50道计算机网络面试题,每一道题目都特别经典,大厂也非常喜欢问。相信大家看完,会有新的收获滴~1. 说说HTTP常用的状态码及其含义?思路: 这道面试题主要考察候选人,是否掌握HTTP状态码这个基础知识点。不管是不…

A successful Git branching model

原文:http://nvie.com/posts/a-successful-git-branching-model/ In this post I present the development model that I’ve introduced for all of my projects (both at work and private) about a year ago, and which has turned out to be very successful. I…

一文详解读写锁

作者 | 磊哥来源 | Java面试真题解析(ID:aimianshi666)转载请联系授权(微信ID:GG_Stone)读写锁(Readers-Writer Lock)顾名思义是一把锁分为两部分:读锁和写锁&#xff0c…

ruby array_Ruby中带有示例的Array.keep_if方法

ruby arrayRuby Array.keep_if方法 (Ruby Array.keep_if Method) In the last articles, we have studied the Array methods namely Array.select, Array.reject and Array.drop_while, all these methods are non–destructive methods which means that they do not impose …

[实战]MVC5+EF6+MySql企业网盘实战(2)——用户注册

写在前面 上篇文章简单介绍了项目的结构,这篇文章将实现用户的注册。当然关于漂亮的ui,这在追后再去添加了,先将功能实现。也许代码中有不合适的地方,也只有在之后慢慢去优化了。 系列文章 [EF]vs15ef6mysql code first方式 [实战…

Calico IP_AUTODETECTION_METHOD

在 Calico 中,IP_AUTODETECTION_METHOD 的配置项用于指定 Calico 如何检测容器的 IP 地址。 一、kubernetes-internal-ip模式 其中,kubernetes-internal-ip 是一种特殊的模式,用于在 Kubernetes 环境中检测容器的 IP 地址。具体作用如下&…