synchronized 锁是可重入锁吗?如何验证?
摘要:举例证明 synchronized锁 是可重入锁,并描述可重入锁的实现原理。
综述
先给大家一个结论:synchronized锁 是可重入锁!
关于什么是可重入锁,通俗来说,当线程请求一个由其它线程持有的对象锁时,该线程会阻塞,而当线程请求由自己持有的对象锁时,如果该锁是重入锁,请求就会成功,否则阻塞。或者说,可重入锁是同一个线程重复请求由自己持有的锁对象时,可以请求成功而不会发生死锁。与多线程并发执行的线程安全不同,可重入强调对单个线程执行时重新进入同一个子程序仍然是安全的。可重入锁又称递归锁。
验证可重入
假设我们现在不知道它是不是一个可重入锁,那我们就应该想方设法来验证它是不是可重入锁?怎么验证呢?看下面的代码!
public class SuperSalesman {
public int ticketNum = 10;
public synchronized void superSaleTickets() {
ticketNum --;
System.out.println("父类售票后,剩余票数:" + ticketNum
+ " " + Thread.currentThread().getName());
try {
Thread.sleep(30);
} catch (InterruptedException e) {
System.out.println("error, " + e);
}
}
}
创建子类:
public class ChildSalesman extends SuperSalesman {
public static void main(String[] args) {
ChildSalesman child = new ChildSalesman();
child.childSaleTickets();
}
public synchronized void childSaleTickets() {
while (ticketNum > 0) {
ticketNum --;
System.out.println("子类售票后,余票为:" + ticketNum
+ " " + Thread.currentThread().getName());
superSaleTickets(); //允许进入,synchronized的可重入性
}
}
@Override
public synchronized void superSaleTickets() {
System.out.println("I am working");
super.superSaleTickets();
}
}
现在运行一下上面的父子类继承代码,我们看一下结果:
子类售票后,余票为:9 main
I am working
父类售票后,剩余票数:8 main
子类售票后,余票为:7 main
I am working
父类售票后,剩余票数:6 main
子类售票后,余票为:5 main
I am working
父类售票后,剩余票数:4 main
子类售票后,余票为:3 main
I am working
父类售票后,剩余票数:2 main
子类售票后,余票为:1 main
I am working
父类售票后,剩余票数:0 main
Process finished with exit code 0
现在可以验证出 synchronized 是可重入锁了吧!因为这些方法输出了相同的线程名称,表明即使递归调用synchronized修饰的方法,也没有发生死锁,证明其是可重入的。
下面是多个方法嵌套调用的例子:
public class SyncTest {
public static void main(String[] args) {
LockTest lock = new LockTest();
lock.method1();
}
}
public class LockTest {
public synchronized void method1() {
System.out.println("method1");
method2();
}
public synchronized void method2() {
System.out.println("method2");
method3();
}
public synchronized void method3() {
System.out.println("method3");
}
}
执行main方法,控制台打印信息如下,说明不会因为之前已经获取过锁还没释放而发生阻塞。即同一线程可执行多个持有同一把锁的方法。
/Library/Java/JavaVirtualMachines/jdk-17.0.2.jdk ...
method1
method2
method3
可以看到调用的三个方法均得到了执行。我们知道synchronized修饰普通方法时,使用的是对象锁,也就是SuperSalesman对象。三个方法的锁都是SuperSalesman对象。我们在子类中执行childSaleTickets方法时,获取了SuperSalesman对象锁,然后在childSomeString时调用了重写父类的superSaleTickets方法,该方法的锁也是SuperSalesman对象锁,然后在其中调用父类的superSaleTickets方法,该方法的锁也是SuperSalesman对象锁。一个锁多次请求,而且都成功了,所以synchronized是可重入锁。
所以在 java 内部,同一线程在调用自己类中其它 synchronized 方法/块或调用父类的 synchronized 方法/块都不会阻碍该线程的执行。就是说同一线程对同一个对象锁是可重入的,而且同一个线程可以获取同一把锁多次,也就是可以多次重入。因为java线程是基于“每个线程(per-thread)”,而不是基于“每次调用(per-invocation)”的(java中线程获得对象锁的操作是以线程为粒度的,per-invocation 互斥体获得对象锁的操作是以每次调用作为粒度的)。
可重入锁的实现原理
看到这里,你终于明白了 synchronized 是一个可重入锁。但是面试官要再问你,可重入锁的原理是什么?
解释一
可重入锁实现可重入性原理或机制是:每一把锁关联一个线程持有者和计数器,当计数器为 0 时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为 1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这把锁,就可以再次拿到这把锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为 0,则释放该锁。
解释二
通过javap -c SynchronizedLock.class 反编译,来解析synchronized可重入锁原理:synchronized通过monitor计数器实现,当执行monitorenter命令时:判断当前monitor计数器值是否为0,如果为0,则说明当前线程可直接获取当前锁对象;否则,判断当前线程是否和获取锁对象线程是同一个线程。若是同一个线程,则monitor计数器累加1,当前线程能再次获取到锁;若不是同一个线程,则只能等待其它线程释放锁资源。当执行完synchronized锁对象的代码后,就会执行monitorexit命令,此时monitor计数器就减1,直至monitor计数器为0时,说明锁被释放了。
结束语
如果您觉得本文对您有帮助,请点一下“推荐”按钮,您的【推荐】将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接;否则,楼兰胡杨保留追究法律责任的权利。
Reference
- https://www.cnblogs.com/incognitor/p/9894604.html
- https://blog.csdn.net/qq_39839075/article/details/100055872
synchronized 锁是可重入锁吗?如何验证?的更多相关文章
- JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁,
如果需要查看具体的synchronized和lock的实现原理,请参考:解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度) 在并发编程中,经常遇到多个线程访问同一个 ...
- Java可重入锁与不可重入锁
可重入锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的. synchronized 和 ReentrantLock 都是可重入锁. 可重入 ...
- Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等
Java 中15种锁的介绍 Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等,在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类 ...
- 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!
网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...
- 探索JAVA并发 - 可重入锁和不可重入锁
本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...
- Java 种15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁等等…
Java 中15种锁的介绍 1,在读很多并发文章中,会提及各种各样的锁,如公平锁,乐观锁,下面是对各种锁的总结归纳: 公平锁/非公平锁 可重入锁/不可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲 ...
- 写文章 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!
网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...
- Java 多线程 -- 理解锁:手动实现可重入锁和不可重入锁
JDK提供的大多数内置锁都是可重入的,也就是 说,如果某个线程试图获取一个已经由它自己持有的锁时,那么这个请求会立 刻成功,并且会将这个锁的计数值加1,而当线程退出同步代码块时,计数器 将会递减,当计 ...
- Java不可重入锁和可重入锁的简单理解
基础知识 Java多线程的wait()方法和notify()方法 这两个方法是成对出现和使用的,要执行这两个方法,有一个前提就是,当前线程必须获其对象的monitor(俗称“锁”),否则会抛出Ille ...
- Java中的常见锁(公平和非公平锁、可重入锁和不可重入锁、自旋锁、独占锁和共享锁)
公平和非公平锁 公平锁:是指多个线程按照申请的顺序来获取值.在并发环境中,每一个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个就占有锁,否者就会加入到等待队列中,以 ...
随机推荐
- 面试题10- I. 斐波那契数列
地址:https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof/ <?php /** 写一个函数,输入 n ,求斐波那契(Fibona ...
- 代码托管平台对比分析:Gitee与GitLab
一.Gitee:本土化服务的深度实践者 Gitee凭借对中国开发者需求的精准洞察,提供了多项针对性优化功能,尤其适合国内团队: 高速稳定的访问体验 服务器均部署于国内,代码拉取.推送及CI/CD流程的 ...
- C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录.追踪C#/.NET/.NET Core领域.生态的每周最新.最实用.最有价值的技术文章.社区动态.优质项目和学习资源等. ...
- FastAPI 错误处理与自定义错误消息完全指南:构建健壮的 API 应用 🛠️
title: FastAPI 错误处理与自定义错误消息完全指南:构建健壮的 API 应用 ️ date: 2025/3/12 updated: 2025/3/12 author: cmdragon e ...
- 一款 .NET 开源、功能强大的远程连接管理工具,支持 RDP、VNC、SSH 等多种主流协议!
前言 今天大姚给大家分享一款基于 .NET 开源(GPL-2.0 license).免费.功能强大的 Windows 远程连接管理工具,支持 RDP.VNC.SSH 等多种主流协议:mRemoteNG ...
- Linux如何从命令行卡死的进程中退出?
Linux如何从命令行卡死的进程中退出? 不知道大家在使用Linux的时候,会不会遇到一些命令,有可能卡顿,有可能执行时间过长(比如使用 find 查找某个文件),这个时候我不想继续执行这个命令了,说 ...
- ATT&CK实战系列(三)红日靶场3
本次打靶练习是一个黑盒测试.没有密码,我们的目标是拿到域控制器的权限,并找到其中的重要文件. 网络拓扑 网卡设置 centos为出网机,第一次运行,需重新获取桥接模式网卡ip. 需重启网络服务serv ...
- 资料推荐-一个神奇的网站educative.io
前言 算法和数据结构一直是笔者心中的痛,笔者曾经阅读过两个材料,但都收效不好,尝试总结下这两个材料: 极客时间的数据结构和算法的课程 优点:适合用于去理解数据结构和算法的基本概念 缺点:不包含题目(这 ...
- Windows Terminal
... Windows Terminal 安装 命令行接口 Windows Terminal 的命令行接口是 wt 因此我们可以在运行输入 wt 打开 Windows Terminal 也可以在资源管 ...
- 学习Linux命令的正确姿势
大家好,我是良许. 大家应该注意到了,最近我的公众号文章末尾都挂着自己录制的<Linux命令从小白到大神>课程. 这个课程我从开始录制到制作完成,足足花了一个半月.如果加上前期的资料收集与 ...