摘要:举例证明 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

synchronized 锁是可重入锁吗?如何验证?的更多相关文章

  1. JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁,

    如果需要查看具体的synchronized和lock的实现原理,请参考:解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度) 在并发编程中,经常遇到多个线程访问同一个 ...

  2. Java可重入锁与不可重入锁

    可重入锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的. synchronized 和   ReentrantLock 都是可重入锁. 可重入 ...

  3. Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等

    Java 中15种锁的介绍 Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等,在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类 ...

  4. 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!

    网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...

  5. 探索JAVA并发 - 可重入锁和不可重入锁

    本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...

  6. Java 种15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁等等…

    Java 中15种锁的介绍 1,在读很多并发文章中,会提及各种各样的锁,如公平锁,乐观锁,下面是对各种锁的总结归纳: 公平锁/非公平锁 可重入锁/不可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲 ...

  7. 写文章 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!

    网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...

  8. Java 多线程 -- 理解锁:手动实现可重入锁和不可重入锁

    JDK提供的大多数内置锁都是可重入的,也就是 说,如果某个线程试图获取一个已经由它自己持有的锁时,那么这个请求会立 刻成功,并且会将这个锁的计数值加1,而当线程退出同步代码块时,计数器 将会递减,当计 ...

  9. Java不可重入锁和可重入锁的简单理解

    基础知识 Java多线程的wait()方法和notify()方法 这两个方法是成对出现和使用的,要执行这两个方法,有一个前提就是,当前线程必须获其对象的monitor(俗称“锁”),否则会抛出Ille ...

  10. Java中的常见锁(公平和非公平锁、可重入锁和不可重入锁、自旋锁、独占锁和共享锁)

    公平和非公平锁 公平锁:是指多个线程按照申请的顺序来获取值.在并发环境中,每一个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个就占有锁,否者就会加入到等待队列中,以 ...

随机推荐

  1. 面试题32 - II. 从上到下打印二叉树 II

    地址:https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/ <?php /** 面试题32 ...

  2. 使用form-create时修改表单数据

    FormCreate 是一个可以通过 JSON 生成具有动态渲染.数据收集.验证和提交功能的表单生成组件.支持5个UI框架,并且支持生成任何 Vue 组件.内置20种常用表单组件和自定义组件,再复杂的 ...

  3. 【2022_12_2】Fibersim安装记录

    Fibersim 安装记录 1. 为什么要写这个文章? 因为我前前后后装了四天才装成功.在我的电脑上,fibersim14 16 17 15 挂到UG10 12 CatiaV5-6R2019 2018 ...

  4. 【Verilog】表达式位宽与符号判断机制

    缘起于p1课下alu算数位移设计.查了好多资料,最后发现还是主要在翻译官方文档.浪费了超多时间啊,感觉还是没搞透,还是先以应用为导向放一放,且用且归纳 1.表达式位宽 expression bit l ...

  5. js回忆录(2) -- 逻辑表达式,条件语句

    之所以要把逻辑表达式和条件语句放一块写一下,完全是因为二者的联系太过紧密,逻辑运算产生布尔值的结果,而条件语句则根据布尔值决定走那个分支. 逻辑与: &&, 首先逻辑与有逻辑与运算功能 ...

  6. Ubuntu如何下载nvidia驱动和Cuda Toolkit

    Ubuntu如何下载nvidia驱动和Cuda Toolkit 前言 ‍ 手快不小心把 nvidia​ 的某个东西删除了,现在不得不全部卸载后再重新安装了. 我再也不敢在不确认内容的情况下,确认删除了 ...

  7. 证件用蓝底、红底、白底照片RGB颜色值

    蓝色: R:67 G:142 B:219: 红色: R:255 G:0 B:0: 白色: R:255 G:255 B:255. * PS:仅供参考,如有特殊要求,请按照相应要求调整色值.

  8. Windows Server评估版/正式版/数据中心版的来源及转换

    评估版: 从微软评估中心下载的版本,相当于微软提供的试用版,可免费使用一段时间.但该版本无法使用 KMS授权或 MAS 永久授权进行激活. 正式版/数据中心版: 从微软许可证中心下载的版本已标识了GL ...

  9. 本地部署overleaf服务帮助latex论文编写

    是的,overleaf是一个很好的服务,提供了立刻上手就可以编写的latex文章的服务.但是,overleaf会面对latex超时,所以需要付钱的情况,这常出现在编写期刊的论文的情况. 因为时效性,所 ...

  10. 『Plotly实战指南』--饼图绘制高级篇

    在数据可视化的世界里,饼图是最直观的展示比例关系的工具之一. 然而,传统的静态饼图已经无法满足现代数据分析的需求.Plotly作为一款强大的可视化库,不仅提供了饼图丰富的基础功能,还支持交互效果和动态 ...