Java中死锁问题及解决方法

 更新时间:2025年12月04日 09:02:19   作者:阿黄学技术  
本文主要介绍了Java中死锁问题及解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

什么是死锁

死锁(Deadlock)是指两个或多个线程在执行过程中,因为争夺资源而造成的一种互相等待的现象,导致这些线程都无法继续执行下去。

死锁产生的四个必要条件:

  • 互斥条件:资源一次只能由一个线程占用
  • 请求与保持条件:线程在持有至少一个资源的同时又请求其他被占用的资源
  • 不剥夺条件:已分配给线程的资源不能被其他线程强行夺取
  • 循环等待条件:存在一个线程等待的循环链

Java中死锁示例

public class DeadlockExample {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Thread1 holds lock1");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread1 waiting for lock2");
                synchronized (lock2) {
                    System.out.println("Thread1 holds lock1 and lock2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("Thread2 holds lock2");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread2 waiting for lock1");
                synchronized (lock1) {
                    System.out.println("Thread2 holds lock1 and lock2");
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

解决死锁的方法

1. 避免嵌套锁

尽量减少锁的嵌套使用,或者确保所有线程以相同的顺序获取锁。

// 修改后的代码 - 确保相同的锁获取顺序
Thread thread1 = new Thread(() -> {
    synchronized (lock1) {
        synchronized (lock2) {
            // 操作资源
        }
    }
});

Thread thread2 = new Thread(() -> {
    synchronized (lock1) {
        synchronized (lock2) {
            // 操作资源
        }
    }
});

2. 使用定时锁

使用tryLock()方法尝试获取锁,如果获取不到则释放已持有的锁。

Lock lock1 = new ReentrantLock();
Lock lock2 = new ReentrantLock();

public void method() {
    while(true) {
        if(lock1.tryLock()) {
            try {
                if(lock2.tryLock()) {
                    try {
                        // 执行操作
                        break;
                    } finally {
                        lock2.unlock();
                    }
                }
            } finally {
                lock1.unlock();
            }
        }
        // 随机休眠避免活锁
        Thread.sleep((long)(Math.random() * 100));
    }
}

3. 使用更高级的并发工具

使用java.util.concurrent包中的高级工具如SemaphoreCountDownLatch等。

4. 死锁检测与恢复

可以通过线程转储(Thread Dump)来检测死锁:

  • 使用jstack工具:jstack <pid>
  • 使用JMX:ThreadMXBean.findDeadlockedThreads()

5. 设置锁超时

if(lock.tryLock(100, TimeUnit.MILLISECONDS)) {
    try {
        // 访问共享资源
    } finally {
        lock.unlock();
    }
} else {
    // 未能获取锁的处理逻辑
}

预防死锁的最佳实践

  • 尽量使用无锁设计或不可变对象
  • 减少锁的作用范围和时间
  • 避免在一个方法中获取多个锁
  • 如果必须获取多个锁,确保所有线程以相同的顺序获取锁
  • 使用并发集合类而非同步集合类
  • 考虑使用读写锁(ReentrantReadWriteLock)替代互斥锁

通过合理的设计和遵循这些原则,可以有效地避免Java程序中的死锁问题。

到此这篇关于Java中死锁问题及解决方法的文章就介绍到这了,更多相关Java 死锁问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java将图片分割为几个部分示例

    java将图片分割为几个部分示例

    这篇文章主要介绍了java将图片分割为几个部分示例,需要的朋友可以参考下
    2014-04-04
  • 如何使用 IntelliJ IDEA 编写 Spark 应用程序(Scala + Maven)

    如何使用 IntelliJ IDEA 编写 Spark 应用程序(Sc

    本教程展示了如何在IntelliJIDEA中使用Maven编写和运行一个简单的Spark应用程序(例如WordCount程序),本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-11-11
  • Java中的封装、继承和多态,你真的都懂了吗

    Java中的封装、继承和多态,你真的都懂了吗

    Java中的封装、继承和多态知识点是学习java必备的基础知识,看似简单,真正理解起来还是有一定难度的,今天小编再次通过实例代码给大家讲解java 封装继承多态知识,感兴趣的朋友一起学习下吧
    2021-05-05
  • SpringBoot整合resilience4j实现接口限流

    SpringBoot整合resilience4j实现接口限流

    最近在开发项目的时候,需要用到限流的功能,本文主要介绍了SpringBoot整合resilience4j实现接口限流,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • java元注解@Inherited的使用详解

    java元注解@Inherited的使用详解

    这篇文章主要介绍了java元注解@Inherited的使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • java利用SMB读取远程文件的方法

    java利用SMB读取远程文件的方法

    这篇文章主要为大家详细介绍了java利用SMB读取远程文件的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • Java实现贪吃蛇游戏源码

    Java实现贪吃蛇游戏源码

    这篇文章主要为大家详细介绍了Java实现贪吃蛇游戏源码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • rocketmq client 日志的问题处理方式

    rocketmq client 日志的问题处理方式

    这篇文章主要介绍了rocketmq client 日志的问题处理方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 用Java编程输出万年历的功能实现

    用Java编程输出万年历的功能实现

    这篇文章主要介绍了用Java编程输出万年历的功能实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • SpringBoot集成P6spy实现自定义SQL日志打印

    SpringBoot集成P6spy实现自定义SQL日志打印

    本文主要介绍了SpringBoot集成P6spy实现自定义SQL日志打印,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07

最新评论