并发王者课-铂金03:一劳永逸-如何理解锁的可重入问题

惰性潮汐
• 阅读 753

欢迎来到《并发王者课》,本文是该系列文章中的第16篇

在前面的文章《铂金1:探本溯源-为何说Lock接口是Java中锁的基础》中,我们提到了锁的可重入问题,并作了简单介绍。鉴于锁的可重入是一个重要概念,所以本文把拿出来做一次单独讲解,以帮助你彻底理解它。

一、锁的可重入所造成的问题

首先,我们通过一段示例代码看锁的可重入是如何导致问题发生,以理解它的重要性。

public class ReentrantWildArea {
    // 野区锁定
    private boolean isAreaLocked = false;

    // 进入野区A
    public synchronized void enterAreaA() throws InterruptedException {
        isAreaLocked = true;
        System.out.println("已经进入野区A...");
        enterAreaB();
    }
    // 进入野区B
    public synchronized void enterAreaB() throws InterruptedException {
        while (isAreaLocked) {
            System.out.println("野区B方法进入等待中...");
            wait();
        }
        System.out.println("已经进入野区B...");
    }

    public synchronized void unlock() {
        isAreaLocked = false;
        notify();
    }
}

在上面这段代码中,我们创建了一片野区,包含了野区A野区B。接着,我们再创建一个打野英雄铠,让他进去野区打野,看看会发生什么事情。

public static void main(String[] args) {
  // 打野英雄铠进入野区
  Thread kaiThread = new Thread(() -> {
    ReentrantWildArea wildArea = new ReentrantWildArea();
    try {
      wildArea.enterAreaA();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  });
  kaiThread.start();
}

输出结果如下:

已经进入野区A...
野区B方法进入等待中...

从结果中可以看到,虽然在同一块野区,但是铠只进入野区A,却没能进入野区B,被阻塞在半道上了。从代码分析上看,野区的两个方法都声明了synchronized,但铠在进入野区A之后,野区进行了锁定isAreaLocked = true,导致铠进入野区B时失败。

这就是典型的锁的可重入所造成的问题。在并发编程时,如果未能处理好这一问题,将会造成线程的无限阻塞,其后果和死锁相当

二、理解锁的可重入

所谓锁的可重入,指的是锁可以被线程 重复递归 调用,也可以理解为对同一把锁的重复获取。 如果未能处理好锁的可重入问题,将会导致和死锁类似的问题。

并发王者课-铂金03:一劳永逸-如何理解锁的可重入问题

三、如何避免锁的可重入问题

避免锁的可重入问题,需要注意两个方面:

  • 尽量避免编写需要重入获取锁的代码
  • 如果需要,使用可重入锁

在Java中,synchronized是可以重入的,下面的这段代码在调用时不会产生重入问题。

public class WildMonster {
    public synchronized void A() {
        B();
    }
    
    public synchronized void B() {
       doSomething...
    }
}

但是,基于Lock接口所实现的各种锁并不总是支持可重入的。在前面的文章中,我们已经展示过不支持重入的Lock接口实现。在具体的场景中使用时,需要务必注意这点。如果需要可重入锁,可以使用Java中的ReentrantLock类。

小结

在本文中,我们再次介绍了锁的可重入问题,并介绍了其产生的原因及避免方式。Java中的synchronized关键字支持锁的可重入,但是其他显示锁并非总是支持这一特性,在使用时需要注意。

此外,需要注意的是,锁的可重入对锁的性能有一定的影响,而且实现起来更为复杂。所以,我们不能说锁的可重入与不可重入哪个好,这要取决于具体的问题

正文到此结束,恭喜你又上了一颗星✨

夫子的试炼

  • 查看ReentrantLock源码,了解其支持可重入的原理。

延伸阅读与参考资料

关于作者

关注公众号【技术八点半】,及时获取文章更新。传递有品质的技术文章,记录平凡人的成长故事,偶尔也聊聊生活和理想。早晨8:30推送作者品质原创,晚上20:30推送行业深度好文。

如果本文对你有帮助,欢迎点赞关注监督,我们一起从青铜到王者

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
3年前
AI攻陷王者荣耀! 打平王者段位选手
DOTA之后,AI攻陷王者荣耀!打平王者段位选手近日,腾讯组织了一场AI与5个王者段位的选手的比赛直播,这次比赛中,击杀人数12:12,AI率先推平人类基地获胜。!(https://oscimg.oschina.net/oscnet/6493545e49c44a0aa76c464bf2fb093b.jpg)
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Stella981 Stella981
3年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Easter79 Easter79
3年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Stella981 Stella981
3年前
JVM 字节码指令表
字节码助记符指令含义0x00nop什么都不做0x01aconst\_null将null推送至栈顶0x02iconst\_m1将int型1推送至栈顶0x03iconst\_0将int型0推送至栈顶0x04iconst\_1将int型1推送至栈顶0x05ic
Python进阶者 Python进阶者
1年前
麻烦问一下xpath标签定位的这个索引是做什么用的?
大家好,我是Python进阶者。一、前言前几天在Python最强王者交流群【杨又串🍻】问了一个Python网络爬虫的问题,问题如下:老师,麻烦问一下xpath标签定位的这个索引是做什么用的,我听网课把这个知识点跳过了?二、实现过程后来【隔壁😼山楂】给了
惰性潮汐
惰性潮汐
Lv1
你曾说过陪我去看一场雪,我在漫漫黑夜静候你的约
文章
4
粉丝
0
获赞
0