首页 > 其他分享 >不可重入锁与死锁

不可重入锁与死锁

时间:2024-12-18 23:01:55浏览次数:6  
标签:重入 调用 lock 不可 死锁 线程

不可重入锁确实可能导致死锁,特别是在同一线程尝试多次获取同一把锁时。如果锁是不可重入的,那么线程在第二次尝试获取锁时会永远阻塞,从而导致死锁。


不可重入锁与死锁的关系

不可重入锁不允许同一个线程多次获取同一把锁。在以下情况下,这种限制会导致死锁:

  1. 递归调用时: 如果一个方法使用了不可重入锁并递归调用自身,那么在递归调用的过程中,线程会尝试重新获取同一把锁,而由于锁是不可重入的,线程会阻塞在第二次锁请求上,最终导致死锁。
  2. 嵌套调用时: 如果一个方法调用了另一个也需要同一把锁的方法,同样会因为不可重入锁导致死锁。

示例:不可重入锁导致死锁

代码示例:

假设我们有一个不可重入锁:

class NonReentrantLock {
    private boolean isLocked = false;

    public synchronized void lock() throws InterruptedException {
        while (isLocked) {
            wait(); // 如果锁已经被占用,等待释放
        }
        isLocked = true;
    }

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

public class DeadlockExample {
    private final NonReentrantLock lock = new NonReentrantLock();

    public void method1() throws InterruptedException {
        lock.lock();
        System.out.println("Method1: Lock acquired");

        // 调用另一个需要同一把锁的方法
        method2();

        lock.unlock();
        System.out.println("Method1: Lock released");
    }

    public void method2() throws InterruptedException {
        lock.lock(); // 再次尝试获取锁
        System.out.println("Method2: Lock acquired");

        lock.unlock();
        System.out.println("Method2: Lock released");
    }

    public static void main(String[] args) {
        DeadlockExample example = new DeadlockExample();
        new Thread(() -> {
            try {
                example.method1();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}
运行结果:

程序会在 method2() 尝试获取锁时发生死锁,因为:

  1. method1() 已经持有了不可重入锁。
  2. method2() 需要获取同一把锁,但由于锁是不可重入的,线程会阻塞在 lock() 调用处。
  3. method1() 无法继续执行释放锁,导致死锁。

为什么可重入锁不会导致死锁?

可重入锁允许同一个线程多次获取同一把锁,而不会被阻塞。这是通过计数器机制实现的:

  • 当一个线程第一次获取锁时,计数器加1。
  • 如果该线程再次获取同一把锁,计数器继续加1。
  • 每次释放锁时,计数器减1,只有当计数器归零时,锁才真正释放。

因此,在递归调用或嵌套调用时,线程可以多次安全地获取锁,不会导致死锁。


如何避免不可重入锁导致的死锁?

  1. 使用可重入锁
    • 替换不可重入锁为可重入锁(例如,Java 中的 ReentrantLock 或使用 synchronized)。
  2. 设计避免嵌套锁定
    • 如果锁是不可重入的,尽量避免在同一线程中多次尝试获取同一把锁。
  3. 重构代码
    • 如果可能,将涉及不可重入锁的嵌套调用重构为非嵌套调用。

总结

不可重入锁确实会导致死锁,尤其是在递归调用或嵌套调用时。如果代码中存在这种场景,建议使用可重入锁(例如 ReentrantLocksynchronized)来避免死锁问题。

标签:重入,调用,lock,不可,死锁,线程
From: https://blog.csdn.net/2302_78571314/article/details/144571549

相关文章

  • 【语法】哈希表与哈希值、可哈希对象与不可哈希对象
    详解Python中的可哈希对象与不可哈希对象(一)——哈希表与哈希值_python中集合不可hash元素可hsh-CSDN博客详解Python中的可哈希对象与不可哈希对象(二)_python中可哈希对象的意思-CSDN博客【理解】哈希函数,即是一种键值对的映射关系,用于大量数据中快速查询、操作数据;也是一种空间......
  • 老板既要又要还要......我用Doris+Hudi把不可能变成了日常
    老板既要又要还要......我用Doris+Hudi把不可能变成了日常探索Doris与Hudi的完美融合智能查询优化华丽转身-不止于快的进化Doris+Hudi湖仓一体的"艺术之美"大数据江湖中流传着这样一个传说:有一位数据科学家,整日为查询性能发愁,夜夜加班优化SQL。直到有一天,他发现了D......
  • node升级为22.*后,npm不可用,npm:无法加载文件
    错误信息如下: 一、打开终端: 二、此由本地策略组引发,可通过命令查看策略:Get-ExecutionPolicy-List如结果都显示Undefined,那代表没有设置安全策略   三、使用以下命令来更改执行策略为RemoteSigned并设置为作用于当前用户Set-ExecutionPolicy-scopeCurren......
  • 打造AI Agent智能体爆款应用势不可挡
    在数字化浪潮的推动下,AIAgent智能体应用正成为IT领域的新宠。它们不仅仅是代码和算法的集合,更是企业数字化转型的加速器。AIAgent智能体应用以其独特的交互方式和智能化处理能力,正在重塑我们的工作和生活方式。一、AIAgent智能体应用的兴起和市场潜力AIAgent智能体应用的......
  • MySQL死锁成因及解决方案
    1.死锁的发生1.1什么是死锁?        死锁是指两个或多个事务在并发执行时,因为资源互相占用而进入一种无限等待的状态,导致无法继续执行的现象。例如:事务A持有资源1,同时请求资源2。事务B持有资源2,同时请求资源1。两者互相等待对方释放资源,最终导致死锁。1.2死锁......
  • MySQL 中如果发生死锁应该如何解决?
    MySQL中如果发生死锁应该如何解决?死锁是指多个事务在执行过程中因资源争用形成的循环等待,导致无法继续执行。MySQL会自动检测死锁并选择一个事务进行回滚,但我们可以通过优化设计和操作来避免和解决死锁问题。1.MySQL如何检测死锁?死锁检测:MySQL的InnoDB存储引擎会维护......
  • 我们来学mysql -- 事务并发之不可重复读(原理篇)
    事务并发之不可重复读题记不可重复读系列文章题记在《事务之概念》提到事务对应现实世界的状态转换,这个过程要满足4个特性这世界,真理只在大炮射程之类,通往和平的道路,非“常人”可以驾驭一个人生活按部就班,人多起来,难免鸡飞狗跳同理现实世界的状态转换映射到数据库,满......
  • 隐侠必备网安利器之 Chrome 扩展(隐蔽身份篇 · 二) 大揭秘,不可错过!
       工欲善其事,必先利其器。东方隐侠安全团队持续收集在渗透测试过程中常用、好用、实用的chrome插件,并按照实际渗透测试流程中的功能、作用、用法分类并测评,同时尽可能扩展相关知识内容。现在将收集的各类chrome扩展分享给各位少侠,以助帮助各位少侠提升渗透测试效率,助力......
  • 是否所有的循环都能用递归代替?为什么?如果不可以,请举例说明
    理论上,所有循环都可以用递归代替。因为循环和递归都是为了实现重复执行一段代码块的功能。循环使用计数器或条件控制重复次数,而递归则通过函数自身调用来实现重复。然而,在实践中,并非所有循环都适合用递归代替。虽然功能上等效,但递归在某些情况下会带来性能和可维护性方面的问题......
  • MySQL的各种锁(表锁,行锁,悲观锁,乐观锁,间隙锁,死锁)
    对于UPDATE、DELETE、INSERT语句,InnoDB会自动给涉及数据集加排他锁(X)。而MyISAM在执行查询语句SELECT前,会自动给涉及的所有表加读锁,在执行增、删、改操作前,会自动给涉及的表加写锁,这个过程并不需要我们去手动操作。那么在特定情况下,我们该如何去加锁呢?下面咱们来认真的......