Java 进阶—死锁造成原因及其解决

news2024/11/23 18:25:03

今天我们来了解一下线程死锁,死锁很好理解,从字面上来看就是锁死了,解不开,在大街上看到一对卧龙凤雏的情侣,怎么说,你们给我锁死,不要分开去霍霍别人

之前我们不是说过,解决线程安全的方法就是给线程上锁,java进阶—线程安全问题,但上锁也会有死锁的情况

那么,死锁是什么?先举个通俗点的例子 小明跟小红分别同时参加两个会议,这时候办公室刚好只有一台笔记本(在小红手上),一台投影仪(在小明手上),这是两个都想要对方的东西,两人互不相让,开始争执,这样都开不成会议,就形成了死锁

在这里插入图片描述
把小明跟小红换成两个线程,所以,一句话,死锁就是两个或两个以上的线程争夺彼此的锁,造成阻塞

从这里我们也可以看到死锁产生的条件

  • 首先,死锁产生需要两个或者两个以上线程 (例子中的小明跟小红)

  • 两个或者两个以上的锁 (例子中的 笔记本跟投影仪)

  • 两个或两个以上线程持有不同锁(例子中小明有投影仪,小红有笔记本)

  • 持有不同锁线程争夺对方的锁 (例子中小明跟小红抢对方的东西)

用代码来解释上述例子

我们按照死锁的四个条件一步一步来

1. 首先有两个线程

一个小明类,一个小红类

2. 两个锁

小明类 里面 有 投影仪锁 , 小红类里面有电脑锁

3. 两个线程持有不同的锁

小明重写run 方法 调用 投影仪 锁

小红重写run 方法 调用 笔记本 锁

4. 持有不同锁调用对方的锁

小明在projector 里面去调用 小红的computer

小红在computer里面去调用 小红的projector


public class XiaoMing  implements Runnable{


    @Override
    public void run() {
        //小明持有投影仪这个锁
        projector();
    }

    /**
     *  投影仪这个锁  static 一个资源
     */
    public static synchronized  void projector() {
        try {
            //线程休眠2秒,目的为了执行慢一点,更方便看出效果
            Thread.sleep(2000);
        } catch (InterruptedException e) { 
            e.printStackTrace();
        }
        System.out.println("小明的投影仪"); 
        // 获取小红的锁
        XiaoHong.computer();
    }
}
public class XiaoHong  implements Runnable{

    @Override
    public void run() { 
        //小红持有笔记本这个锁
        computer();
    }

    /**
     * 笔记本这个锁   static 一个资源
     */
    public static synchronized  void computer() {
        try {
            //线程休眠2秒
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("小红的笔记本");
        //获取小明的锁
        XiaoMing.projector();
    }
}

我们去启动这两个线程

    public static void main(String[] args) {
        //创建小红线程
        XiaoHong xiaoHong =new XiaoHong();
        Thread thread =new Thread(xiaoHong);
        //创建小明线程
        XiaoMing xiaoMing = new XiaoMing();
        Thread thread1 =new Thread(xiaoMing);
        //启动
        thread.start();
        thread1.start();
    }

执行结果:

在这里插入图片描述
程序在打印两个结果后,两个程序在相互争夺资源,程序停止需要借助外力

解决死锁也就很简单了,我们不去拿对方的锁就好了

在这里插入图片描述
这一步,我们不去调用对方的锁,

看看效果:
在这里插入图片描述
可以看到程序正常终止了

要是不太明白,我们再来看一个更直观的代码:(注意看代码中的注释)

还是有这么两个资源,电脑跟投影仪


public class Person implements Runnable {
    /**
     * 只有一份资源,电脑  跟 投影仪
     */
    static final Computer COMPUTER = new Computer();
    static final Projector PROJECTOR = new Projector();

    /**
     * 类型 0 代表 小红  1代表小明
     */
    int  type;
    /**
     * 人名
     */
    String  name;

    public Person(int type, String name) {
        this.type = type;
        this.name = name;
    }

    @Override
    public void run() {
       //开始抢占资源
        try {
            getSource();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void getSource() throws InterruptedException {
        //让小明先拿投影仪
        if (type==1) {
            synchronized (PROJECTOR) {
                System.out.println(this.name+"获得投影仪");
                Thread.sleep(2000);
                //小明拿到投影仪,又想去拿电脑
                synchronized (COMPUTER) {
                    System.out.println(this.name+"获得电脑");
                }
            }

        }else {
            //小红拿到电脑,又想去拿投影仪
            synchronized (COMPUTER) {
                System.out.println(this.name+"获得电脑");
                Thread.sleep(1000);

                synchronized (PROJECTOR) {
                    System.out.println(this.name+"获得投影仪");
                }
            }

        }
    }

}

启动两个线程

  public static void main(String[] args) {

        Person person =new Person(1,"小明");
        Person person2 =new Person(0,"小红");
        Thread thread =new Thread(person);
        Thread thread1 =new Thread(person2);
        thread.start();
        thread1.start();
    }

执行结果:
在这里插入图片描述
程序进入了死锁

怎么解决?一样的,获取到锁的同时不去调用对方的锁,我们这两段代码放到外边来

在这里插入图片描述
变成下面这样

在这里插入图片描述

package com.xrp.flinkDemo.demo;

public class Person implements Runnable {
    /**
     * 只有一份资源,电脑  跟 投影仪
     */
    static final Computer COMPUTER = new Computer();
    static final Projector PROJECTOR = new Projector();

    /**
     * 类型 0 代表 小红  1代表小明
     */
    int  type;
    /**
     * 人名
     */
    String  name;

    public Person(int type, String name) {
        this.type = type;
        this.name = name;
    }

    @Override
    public void run() {
       //开始抢占资源
        try {
            getSource();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void getSource() throws InterruptedException {
        //让小明先拿投影仪
        if (type==1) {
            synchronized (PROJECTOR) {
                System.out.println(this.name+"获得投影仪");
                Thread.sleep(2000);
            }

            synchronized (COMPUTER) {
                System.out.println(this.name+"获得电脑");
            }

        }else {
            //小红拿到电脑,又想去拿投影仪
            synchronized (COMPUTER) {
                System.out.println(this.name+"获得电脑");
                Thread.sleep(1000);
            }


            synchronized (PROJECTOR) {
                System.out.println(this.name+"获得投影仪");
            }

        }
    }

}

再执行看看:
在这里插入图片描述
可以发现解决了死锁问题,并且都获得了想要的资源

好了,以上便是死锁原因以及避免死锁方法了,主要就是不要在持有一个锁里面再去获取别的锁

【完】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/622700.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GoogleTest之创建Mock

目录 MOCK_METHODmock方法的访问属性mock非虚函数mock自由函数Nice/Strict/Naggymock方法简化参数mock具体类的替代方法代理给fake mock是用来模拟对象,隔离边界的一种测试方法,以便在开发阶段不需要依赖第三方或其他依赖项可以进行独立的测试。 MOCK_ME…

MySQL调优系列(六)——查询优化

一、查询慢的原因 查询速率受网络、CPU、IO、上下文切换、系统调用、生成统计信息、锁等待时间等因素影响。 举个常见面试题: 一个表非常非常大,上亿级别的数据,性能会变慢嘛?如果表有索引 答:增删改会变慢。&#xf…

Python可视化分析项目高分课设

今天给大家分享一个基于python的django框架结合爬虫以及数据可视化和数据库的项目,该项目总体来说还是挺不错的,下面针对这个项目做具体介绍。 1:项目涉及技术: 项目后端语言:python 项目页面布局展现:前…

数据结构--队列

文章目录 队列基础队列的实现链表实现环形数组实现tail一直加的问题容量处理 队列的使用 队列基础 queue 是以顺序的方式维护的一组数据集合 相对于链表来说,队列操作数据的位置是固定的只能2端操作。 在一端添加数据,从另一端移除数据。习惯来说&#…

高完整性系统(3):Threat Modelling

文章目录 基础安全性质保密性(Confidentiality)完整性(Integrity)可用性(Availability)认证(Authentication)不可抵赖性(Non-repudiation)访问控制&#xff0…

从开源软件看动态内存分配

动态内存分配 我们通常在C里面动态分配内存,会写出下面这样的代码: struct header {size_t len;unsigned char *data; }; 随后为data malloc一段内存出来,那么还有其他办法吗? 那便是弹性数组!在阐述本节之前&#xff…

数据安全有隐患?金仓数据60秒邀你闯关破题赢奖品

数字时代 数据成为宝贵资产 数据的安全 更是关乎行业可持续发展 关乎社会的稳定和国家战略 数据库作为 数据安全的首要防线 如何纵深防御 保障数据安全合规 满足新应用新场景下的安全防护要求 金仓数据60秒 发布多个视频为您详细剖析 同时,小编发起“闯关挑战”活动…

【Linux】14. 文件缓冲区

1. 文件缓冲区的引出 如上现象,在学习完文件缓冲区之后即可解释 2. 认识缓冲区 缓冲区的本质就是内存当中的一部分,那么是谁向内存申请的? 是属于谁的? 为什么要存在缓冲区呢? 道理是如此,在之前的学习过…

基于matlab仿真带有飞机的虚拟场景

一、前言 此示例演示如何通过 MATLAB接口使用空间鼠标。 开始此示例后,带有飞机的虚拟场景将显示在 Simulink 3D 动画查看器中。您可以使用空格鼠标在场景中导航平面。通过按下设备按钮 1,您可以在当前平面位置放置标记。 此示例需要空间鼠标或其他兼容设…

Neuralangelo AI - 视频生成3D模型

NVIDIA Research 宣布了 Neuralangelo,这是一种创新的 AI 模型,它利用神经网络的力量从 2D 视频剪辑中重建详细的 3D 结构。 Neuralangelo 能够生成逼真的建筑物、雕塑和其他现实世界物体的虚拟复制品,展示了 AI 在 3D 重建领域的非凡潜力。…

十个国内可用的智能AI模型

AI语言模型,就是一种利用机器学习和自然语言处理技术进行文本生成的算法。其基于大量已有的语料库进行训练,建立出一个能够理解自然语言规律和特征的语言模型。对于输入的文本、任务和目标,AI语言模型可以快速生成对应的结果。 在实际应用中&…

Flume入门监控端口数据官方案例

Flume安装部署 相关地址 Flume官网地址:http://flume.apache.org/文档查看地址:http://flume.apache.org/FlumeUserGuide.html下载地址:http://archive.apache.org/dist/flume/ 安装 将apache-flume-1.9.0-bin.tar.gz上传到linux的/opt/s…

责任链模式的学习与使用

1、责任链模式的学习 责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许你将请求沿着处理链进行传递,直到有一个处理者能够处理该请求。责任链模式将请求的发送者和接收者解耦,使多个对象都有机…

计算机网络通信过程

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和…

案例|某城商行Zabbix 监控架构分享

编者荐语: 东莞银行董天保将出席7月份Zabbix大会分享案例经验,欢迎参加! 以下文章来源于有田菜也香 ,作者AcidGo 东莞银行董天保先生将于7月份参加Zabbix大会分享使用经验,欢迎扫码参加! 【导读】某银行…

openCV(三)绘制几何图形

openCV内置了几何图形绘制函数,通过简单的操作就可以绘制几何图形。例如,可以绘制直线、矩形、圆形、椭圆、多边形、文字等,分别对应函数cv2.line()、cv2.rectangle()、cv2.circle()、cv2.ellipse()、cv2.polylines()、cv2.putText()。 下面来…

Mysql进阶【3】论述Mysql优化

1.通过explain查看sql的详细信息 Mysql的sql优化企业里边主要是对慢sql进行优化,对语句进行优化,对索引进行优化 通过explain查看sql的详细信息,并且分析sql语句存在的问题,比如有没有使用到索引、使用了索引还是慢是不是索引设…

第一章_从减库存聊起

在多线程高并发场景下,为了保证资源的线程安全问题, jdk 为我们提供了 synchronized 关键字和 ReentrantLock 可重入锁,但是它们只能保证一个 jvm 内的线程安全。在分布式集群、微服务、云原生横行的当下,如何保证不同进程、不同…

2023年京东618预售数据:传统滋补成预售黑马,预售额超27亿

这一期主要分享一下此次京东618预售期间的一个黑马行业——传统滋补。不管是从预售量和预售额来看,传统滋补品类的成绩都是此次大促中的佼佼者。 究其原因,近几年养生滋补也掀起了一股“国潮风”。在小红书、抖音等社交平台上,关于“健康养生…

车载摄像头专用——拓尔微低功耗超高集成PMIC TMI7205B

“2023将是汽车行业的大变革之年,全球迎来L2向L3/L4跨越窗口。”越高级别的自驾对周围环境感知要求越高,车载摄像头“高清化”势不可挡,目前已从传统的100万直接跃升至800万像素摄像头,甚至在供应层面,已有超1500万高像…