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线程实现时间动态显示,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • SpringMVC实现账号只能在一处登陆

    SpringMVC实现账号只能在一处登陆

    这篇文章主要为大家详细介绍了SpringMVC如何实现账号只能在一处登陆,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • SpringBoot中使用 POI的示例代码

    SpringBoot中使用 POI的示例代码

    这篇文章主要介绍了SpringBoot中使用POI的实例详解,包括引入poi的jar包和创建excel的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • 一文告诉你为什么要重写hashCode()方法和equals()方法

    一文告诉你为什么要重写hashCode()方法和equals()方法

    本篇文章带大家了解一下为什么重写hashCode()方法和equals()方法,文中有非常详细的说明以及代码示例,对正在学习java的小伙伴们很有帮助,需要的朋友可以参考下
    2021-05-05
  • 基于jdk动态代理和cglib动态代理实现及区别说明

    基于jdk动态代理和cglib动态代理实现及区别说明

    这篇文章主要介绍了基于jdk动态代理和cglib动态代理实现及区别说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • Java多线程ForkJoinPool实例详解

    Java多线程ForkJoinPool实例详解

    这篇文章主要介绍了Java多线程ForkJoinPool实例详解,涉及forkjoin框架的相关内容,需要的朋友可以参考下。
    2017-09-09
  • Java实例讲解反射机制是怎么一回事

    Java实例讲解反射机制是怎么一回事

    Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法
    2022-03-03
  • java为移动端写接口开发实例

    java为移动端写接口开发实例

    本篇文章主要介绍了java如何为移动端写接口,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • 详解Java中类的加载顺序

    详解Java中类的加载顺序

    Java中什么时候类加载,第一次需要使用类信息时加载。类加载的原则:延迟加载,能不加载就不加载。下面这篇文章主要介绍了Java中类的加载顺序,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-01-01
  • Web三大组件之Filter,Listener和Servlet详解

    Web三大组件之Filter,Listener和Servlet详解

    这篇文章主要为大家详细介绍了Web三大组件之Filter,Listener和Servlet,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03

最新评论