Java死锁的产生原因及解决方法总结

 更新时间:2023年11月06日 09:24:22   作者:一一哥Sun  
Java中的死锁是指多个线程同时占用一些共享资源且彼此相互等待,从而导致所有的线程都被阻塞,不能继续执行程序的情况,本文小编给大家介绍了Java死锁的产生原因及解决方法总结,需要的朋友可以参考下

一. 死锁

1. 概念

Java中的死锁是指多个线程同时占用一些共享资源且彼此相互等待,从而导致所有的线程都被阻塞,不能继续执行程序的情况。这就好比在一个十字路口,没有交警也没有红绿灯指挥通行,所有的车辆都占据道路且互相等待对方让出路权,此时就很容易造成道路堵死,这其实就是道路的“死锁”。如下图所示:

2. 死锁案例

虽然我们现在已经知道了死锁的概念,但具体什么时候会产生死锁,相信很多小伙伴肯定还是弄不不清楚。所以接下来就给大家设计一个会产生死锁的代码案例,如下所示:

/**
 * @author 一一哥Sun
 * @company 千锋教育
 */
public class Demo21 {
    // 定义2个锁定的对象
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void method1() {
        // 锁定对象1
        synchronized (lock1) {
            System.out.println("Method 1: 获取对象lock1的锁");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 锁定对象2
            synchronized (lock2) {
                System.out.println("Method 1: 获取对象lock2的锁");
            }
        }
     }

    public void method2() {
        // 锁定对象2
        synchronized (lock2) {
            System.out.println("Method 2: 获取对象lock2的锁");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 锁定对象1
            synchronized (lock1) {
                System.out.println("Method 2: 获取对象lock1的锁");
            }
        }
    }

    public static void main(String[] args) {
        final Demo21 example = new Demo21();

        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                example.method1();
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            public void run() {
                example.method2();
            }
        });

        //开启线程
        thread1.start();
        thread2.start();
    }
}

在上面的案例中,定义了两个方法method1和method2,这两个方法分别占用了lock1和lock2两个锁,并且在执行过程中会互相等待对方的锁,从而形成了死锁。如果我们运行该程序,就会看到两个线程互相等待对方释放自己占用的锁,这最终会导致所有的线程都被阻塞。上述案例中死锁的产生原因,如下图所示:

根据上面的案例,你可以总结出会导致死锁的条件吗?我们继续往下看。

3. 产生条件

其实一个Java程序要想产生死锁,也并不是那么容易,只有同时满足以下条件才行:

互斥条件:多个线程需同时访问一个共享资源,但每次只能有一个线程访问该资源;

请求和保持条件:一个线程在持有一个资源的同时,还想请求另一个资源;

不可剥夺条件:已经分配的资源不能被其他线程剥夺;

循环(环路)等待条件:多个线程形成了一个循环等待资源的链路,例如线程A等待线程B释放自己所占用的资源,线程B等待线程C释放自己所占用的资源,而线程C又等待线程A释放自己所占用的资源。

只有同时满足了以上条件,程序中才会产生死锁。既然我们现在知道了死锁的产生条件,那又该怎么解决呢?

4. 解决办法

我们知道,当出现死锁时,所有的线程都会被阻塞,且不能再继续执行程序,所以我们必须解决死锁。一般情况下,我们可以通过以下方式来避免线程死锁:

避免使用多个锁;

尽可能减少同步代码块的长度;

尝试改变锁的获取顺序,避免线程之间形成循环等待;

使用定时锁,当等待时间超过一定的时间值后就自动释放锁

以上就是打破死锁条件的解决办法,但是具体放到Java代码中又是怎么样的呢?接下来就把上面产生死锁的代码修改一下,解决死锁问题。

5. 案例优化

接下来就把上面产生死锁的案例优化一下,解决掉案例中的死锁,代码如下:

public class Demo22 {
    // 定义2个锁定的对象
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void method1() {
        //锁定对象
        synchronized(lock1) {
            System.out.println("Method 1: 获取对象锁lock 1");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            synchronized(lock2) {
                System.out.println("Method 1: 获取对象锁lock 2");
            }
        }
    }

    public void method2() {
        synchronized(lock1) {
            System.out.println("Method 2: 获取对象锁lock 1");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            synchronized(lock2) {
                System.out.println("Method 2: 获取对象锁lock 2");
            }
        }
    }

    public static void main(String[] args) {
        final Demo22 demo = new Demo22();

        //定义两个线程
        Thread thread1 = new Thread(new Runnable() {
        	@Override
            public void run() {
            	demo.method1();
            }
        });

        Thread thread2 = new Thread(new Runnable() {
        	@Override
            public void run() {
            	demo.method2();
            }
        });

        //开启线程
        thread1.start();
        thread2.start();
    }
}

上面的这个案例与之前的案例代码几乎一样,但与之不同的是,本案例中的方法method1和method2,都是先占用lock1锁,再占用lock2锁,这样就避免了死锁的发生,因为这两个方法占用锁的顺序是一致的。所以我们在编写多线程代码时,需要特别注意线程死锁的问题,避免影响程序的正常执行。

二. 结语

至此,小编就把Java中的死锁给大家讲解完毕了,现在你明白了吗?我们在面试时经常会有面试官考察死锁相关的内容,比如死锁是怎么产生的?如何避免死锁?所以今天的内容很重要,请各位一定要牢牢掌握哦。

以上就是Java死锁的产生原因及解决方法总结的详细内容,更多关于Java死锁的资料请关注脚本之家其它相关文章!

相关文章

  • SpringBoot实战之实现结果的优雅响应案例详解

    SpringBoot实战之实现结果的优雅响应案例详解

    这篇文章主要介绍了SpringBoot实战之实现结果的优雅响应案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • java文件对话框过滤特定文件类型示例

    java文件对话框过滤特定文件类型示例

    文件作为存储数据的单元,会根据数据类型产生很多分类,也就是所谓的文件类型。在对数据文件进行操作时,常常需要根据不同的文件类型来作不同的处理。本实例实现的是读取文件夹指定类型的文件并显示到表格控件中
    2014-02-02
  • Springboot的启动原理详细解读

    Springboot的启动原理详细解读

    这篇文章主要介绍了Springboot的启动原理详细解读,springboot项目一般都是打包成jar包直接运行main方法启动,当然也可以跟传统的项目一样打包war包放在tomcat里面启动.那么springboot怎么直接通过main方法启动呢,需要的朋友可以参考下
    2023-11-11
  • java反射之方法反射的基本操作方法

    java反射之方法反射的基本操作方法

    下面小编就为大家带来一篇java反射之方法反射的基本操作方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • JAVA maven项目使用钉钉SDK获取token、用户

    JAVA maven项目使用钉钉SDK获取token、用户

    这篇文章主要介绍了JAVA maven项目使用钉钉SDK获取token、用户,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • SpringMVC 拦截器不拦截静态资源的三种处理方式方法

    SpringMVC 拦截器不拦截静态资源的三种处理方式方法

    本篇文章主要介绍了SpringMVC 拦截器不拦截静态资源的三种处理方式方法,详细的介绍了三种方法,有兴趣的可以了解一下。
    2017-01-01
  • springboot项目部署在linux上运行的两种方式小结

    springboot项目部署在linux上运行的两种方式小结

    这篇文章主要介绍了springboot项目部署在linux上运行的两种方式小结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • java编译命令和启动命令的使用方式

    java编译命令和启动命令的使用方式

    Java开发中,编译源文件需使用javac命令,该命令能将.java文件编译成.class字节码文件,后者可在JVM上运行,常用编译选项包括-d指定输出目录,-classpath设置类搜索路径等,启动Java程序使用java命令,它加载并运行包含main方法的类
    2024-10-10
  • Java实现插入公式到PPT的示例代码

    Java实现插入公式到PPT的示例代码

    PPT中可插入公式,用于放映时演示相关内容的论证、推算的依据。通过代码,我们可借助特定的工具来实现在PPT中的插入公式,本文将对此作详细介绍
    2022-07-07
  • 基于GeoTools和SpringBoot的省域驾车最快路线规划方法

    基于GeoTools和SpringBoot的省域驾车最快路线规划方法

    本文探讨基于GeoTools与SpringBoot的省域驾车最快路线规划方法,解决复杂路况与地理因素影响,通过天地图API计算并存储距离数据,展示湖南、新疆、黑龙江等地的路线成果,为交通与经济影响评估提供参考,感兴趣的朋友快来一起学习吧
    2025-07-07

最新评论