Java死锁

本文详细介绍了Java中的死锁现象,包括死锁的定义、产生条件及如何解决死锁问题。同时,提供了Java简单死锁的示例以及通过jps、jstack、jcmd和jconsole等工具排查死锁的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.死锁是什么?

死锁指两个或者两个以上的线程在执行过程中,去争夺同样一个共享资源,造成的相互等待的现象,如果没有外部干预,线程会一直阻塞,无法往下执行,这样一直处于相互等待资源的线程叫做死锁线程。

二.为什么会有死锁?(死锁发生的条件)

同时满足四个条件就会产生死锁。

(1)互斥条件:一个资源每次只能被一个线程使用。

(2)请求与保持条件:一个线程因为请求资源而阻塞时,对已经获得的资源保持不放。

(3)不剥夺条件:线程已经获得的资源,在未使用完之前,不能强行剥夺。

(4)循环等待条件:若干线程之间形成一个头尾相接的循环等待资源的关系。

三.如何解决死锁问题

死锁发生后,只能通过人工干预来解决,比如重启服务或者杀死这个线程。所以只能在编码时避开可能出现死锁的问题,而按照死锁发生的四个条件,只用破坏其中的一种就能避免死锁的发生。其中互斥条件没有办法被破坏,因为互斥条件是互斥锁的基本约束,其他的三个条件都有办法破坏。

对于请求和保持条件:一次性申请所有的资源,就不存在锁等待。

对于不可剥夺条件:占用资源的线程在进一步申请其他资源的时候,如果申请不到,可以主动去释放它占有的资源。

对于循环等待条件:可以按序申请来预防,线程在申请资源时按照顺序资源,线性化来避免循环。

四.Java中简单的死锁demo

    // a对象
    public static Object a = new Object();
    // b对象
    public static Object b = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            // 获取对象a的锁
            System.out.println(Thread.currentThread().getName() + "请求" + a + "的锁");
            synchronized (a) {
                System.out.println(Thread.currentThread().getName() + "获取到" + a + "的锁");
                // 线程等待2s
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 获取对象b的锁
                System.out.println(Thread.currentThread().getName() + "请求" + b + "的锁");
                synchronized (b) {
                    System.out.println(Thread.currentThread().getName() + "获取到" + b + "的锁");
                }
            }
        }).start();

        new Thread(() -> {
            // 获取对象b的锁
            System.out.println(Thread.currentThread().getName() + "请求" + b + "的锁");
            synchronized (b) {
                System.out.println(Thread.currentThread().getName() + "获取到" + b + "的锁");
                // 线程等待2s
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 获取对象a的锁
                System.out.println(Thread.currentThread().getName() + "请求" + a + "的锁");
                synchronized (a) {
                    System.out.println(Thread.currentThread().getName() + "获取到" + a + "的锁");
                }
            }
        }).start();
    }

五.如何排查死锁问题

方法一:通过jps命令找到运行的Java线程id,再通过jstack命令查看线程是否有死锁

方法二: 通过jps命令找到运行的Java线程id,再通过jcmd命令查看线程是否有死锁

方法三:使用Java内置性能分析工具jconsole

jps:列出正在运行的虚拟机进程。

jcmd:列出当前运行的所有虚拟机。

jstack:生成当前时刻的虚拟机线程快照。

jmap:生成堆转储快照。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

psvm_code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值