【JavaEE初阶】 死锁详解

news2024/10/5 2:09:57

文章目录

  • 🎋死锁的概念
  • 🌳死锁的三个典型情况
    • 🚩一个线程一把锁
    • 🚩两个线程两把锁
    • 🚩n个线程m把锁(哲学家就餐问题)
  • 🎄如何破除死锁
    • 🚩破坏循环等待

本文重点:

  • 死锁咋回事

  • 死锁的三个典型情况

  • 死锁的四个必要条件

  • 如何破除死锁

🎋死锁的概念

死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。此时就发生了死锁

🌳死锁的三个典型情况

🚩一个线程一把锁

一个线程一把锁,但是都是不可重入锁。该线程争对这个锁连续加锁就会陷入死锁

在这里插入图片描述

什么叫不可重入锁呢?为什么不可重入锁会造成死锁呢?

一个线程没有释放锁, 然后又尝试再次加锁

  • 按照之前对于锁的设定, 第二次加锁的时候, 就会阻塞等待.

  • 直到第一次的锁被释放, 才能获取到第二个锁.

  • 但是释放第一个锁也是由该线程来完成, 结果这个线程已经躺平了, 啥都不想干了, 也就无法进行解锁操作.

  • 这时候就会死锁

举个例子:

一个滑稽老铁去上厕所,反锁厕所们后,然后不小心一个闪现出来了,还失忆了,这时候厕所没人,但是处于锁的状态,后面等待的人无法进入
在这里插入图片描述
这样的锁称为不可重入锁

值得注意的是:Java 中的synchronized是可重入锁, 因此没有上面锁死的问题

🚩两个线程两把锁

两个线程两把锁,把这两个线程先分别获取一把锁,然后再同时尝试获取对方的锁。
在这里插入图片描述
举个例子:

阿强和阿珍一起去饺子馆吃饺子.
阿强点了一份汤,阿珍点了一份饺子
这时候他们都想尝尝对方的东西,这时候就有
阿强说:你先给我吃饺子,我再给你喝汤
阿珍说:你先给我和汤,我再给你吃饺子
如果这俩人彼此之间互不相让, 就构成了死锁.
饺子和汤相当于是两把锁, 这两个人就是两个线程

在这里插入图片描述
这时候阿珍和阿强就会发生僵持,发生死锁

接下来我我们写个程序来模拟一下

代码如下:

public class EatLock {
    public static void main(String[] args) {
        Object soup = new Object();
        Object dumplings = new Object();

        Thread thread1 = new Thread(()->{
           synchronized (soup) {
               //等待是为了让另一个线程有时间给第一层加锁
               try {
                   Thread.sleep(3000);

               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
               synchronized (dumplings) {
                   System.out.println("阿珍喝到了汤,也吃到了饺子");
               }
           }
        },"阿珍");
        thread1.start();
        Thread thread2 = new Thread(()->{
            synchronized (dumplings) {
                //等待是为了让另一个线程有时间给第一层加锁
                try {
                    Thread.sleep(1000);

                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (soup) {
                        System.out.println("阿强吃到了饺子,也喝到了汤");
                }
            }
        },"阿强");
        thread2.start();
    }
}

代码结果就是堵塞,这里就不展示了

这里我们通过jconsole命令来进行查看一下各个线程的状态,不会使用的读者可以到博主写的《【JavaEE初阶】线程的概念与创建》里面学习详细的查看方法,这里就不做过多赘述了

在这里插入图片描述
在这里插入图片描述
这里我们可以看到阿强与阿珍都处于等待状态

🚩n个线程m把锁(哲学家就餐问题)

问题是这样的:

  • 有个桌子, 围着一圈 哲 学 家, 桌子中间放着一盘意大利面. 每个哲学家两两之间, 放着一根筷子
    在这里插入图片描述
  • 每个 哲 学 家 只做两件事: 思考人生 或者 吃面条. 思考人生的时候就会放下筷子. 吃面条就会拿起左
    右两边的筷子(先拿起左边, 再拿起右边)
    在这里插入图片描述
  • 如果 哲 学 家 发现筷子拿不起来了(被别人占用了), 就会阻塞等待.

在这里插入图片描述

  • [关键点在这] 假设同一时刻, 五个 哲 ♂ 家 同时拿起左手边的筷子, 然后再尝试拿右手的筷子, 就会发现右手的筷子都被占用了. 由于 哲 ♂ 家 们互不相让, 这个时候就形成了 死锁

在这里插入图片描述
死锁是一种严重的 BUG!! 导致一个程序的线程 “卡死”, 无法正常工作

🎄如何破除死锁

想要破除死锁,首先的弄懂java死锁的四个必要条件

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

  1. 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用

  2. 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。

  3. 请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。

  4. 循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。

当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。

由于前三个条件是操作系统的特性,所以我们无法改变,我们能做其中最容易破坏的就是 “循环等待”.

🚩破坏循环等待

最常用的一种死锁阻止技术就是锁排序. 假设有 N 个线程尝试获取 M 把锁, 就可以针对 M 把锁进行编号
(1, 2, 3…M).

N 个线程尝试获取锁的时候, 都按照固定的按编号由小到大顺序来获取锁. 这样就可以避免环路等待.

比如我们上述阿强与阿珍吃饭的例子

就是因为两个线程对于加锁的顺序没有约定, 就容易产生环路等待

解决方法:

我们预定好先给阿珍喝汤,再给阿强吃饺子,这样就不会产生死锁了,修改代码如下:

public class EatLock {
    public static void main(String[] args) {
        Object soup = new Object();
        Object dumplings = new Object();

        Thread thread1 = new Thread(()->{
           synchronized (soup) {
               //等待是为了让另一个线程有时间给第一层加锁
               try {
                   Thread.sleep(3000);

               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
               synchronized (dumplings) {
                   System.out.println("阿珍喝到了汤,也吃到了饺子");
               }
           }
        },"阿珍");
        thread1.start();
        Thread thread2 = new Thread(()->{
            synchronized (soup) {
                //等待是为了让另一个线程有时间给第一层加锁
                try {
                    Thread.sleep(1000);

                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (dumplings) {
                        System.out.println("阿强吃到了饺子,也喝到了汤");
                }
            }
        },"阿强");
        thread2.start();
    }
}

运行结果如下:
在这里插入图片描述
哲学家问题也同理,这里就不做过多赘述了

⭕总结
关于《【JavaEE初阶】 死锁》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

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

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

相关文章

2023年中国石油催化裂化剂行业供需、竞争格局及市场规模分析[图]

催化裂化是石油炼制过程之一,是在热和催化剂的作用下使重质油发生裂化反应,转变为裂化气、汽油和柴油等的过程。中国原油加工量在这一阶段逐年提升,2022年国内原油加工量67589.7万吨。 2016-2022年中国原油加工量情况 资料来源:国…

learn编码器

目录 1、编码器的作用 2、编码器的结构图 3、代码实现如下 1、编码器的作用 编码器用于对输入进行指定的特征提取的过程,也称为编码,由 N 个编码器层堆叠而成 2、编码器的结构图 3、代码实现如下 import numpy as np from torch.autograd import Vari…

RabbitMQ开启消息跟踪日志(trace)

Trace 是Rabbitmq用于记录每一次发送的消息,方便使用Rabbitmq的开发者调试、排错。 1、启动Tracing插件 在RabbitMQ中默认是关闭的,需手动开启。此处rabbitMQ是使用docker部署的 ## 进入rabbitMq中 docker exec -it rabbitmq1 bash ## 启动日志插件 r…

基于图像的照明(IBL)简明教程

基于图像的照明基本上将图像中的所有像素视为光源。 通常,从全景高动态范围 (HDR) 图像创建的环境贴图(通常是立方体贴图)将用作纹理获取的源。 推荐:用 NSDT编辑器 快速搭建可编程3D场景 假设阴影物体是不透明的,我们…

lazada商品评论数据接口,lazada商品评论API接口,lazadaAPI接口

lazada商品评论数据接口可以按照以下步骤获取: 注册Lazada开发者账号,创建API密钥和访问令牌。调用Lazada Open API中的Product Review API,提供商品的SKU或Seller SKU参数,即可获取该商品的所有评论。 Lazada商品评论数据接口封…

【Spring Boot从入门到实战】RabbitMQ消息队列 —— RabbitMQ入门

💠一名热衷于分享知识的程序员 💠乐于在CSDN上与广大开发者交流学习。 💠希望通过每一次学习,让更多读者了解我 💠也希望能结识更多志同道合的朋友。 💠将继续努力,不断提升自己的专业技能,创造更多价值。🌿欢迎来到@"衍生星球"的CSDN博文🌿 🍁本…

Web安全教程(超详细!从入门到精通!零基础可学!)

Web简介: Web 即全球广域网,也称为万维网,它是一种基于超文本和HTTP的、全球性的、动态交互和浏览信息提供了图形化的、易于访问的直观界面,其中的文档及超级链接将Internet上的信息节点组织成一个互为关联的网状结构。 万维网常…

2023年中国数控系统市场发展历程及趋势分析:数控系统市场规模将持续扩大[图]

数控系统是根据计算机存储器中存储的控制程序,执行部分或全部数值控制功能,并配有接口电路和伺服驱动装置的专用计算机系统。通过利用数字、文字和符号组成的数字指令来实现一台或多台机械设备动作控制,它所控制的通常是位置、角度、速度等机…

了解5个区别,FPmarkets用烛台和Renko图实现交易翻倍

很多投资者不知道日本烛台图表和Renko图表的区别,在交易中出现好的机会而把握不住,今天FPmarkets就和投资者一起了解烛台图表和Renko图表的区别,在今后的交易中能第一时间抓住机会,从而盈利。 首先,Renko图表是平滑的…

Linux系统卡顿处理记录(Debian)

问题现象描述 现象linux操作系统卡顿(就是很慢),但是系统任然能够使用。 文章一步步的排查并且定位问题。 排查步骤 1. 使用top命令查看CPU是否占用过高。(未发现)排除问题 2. 使用df -h查看硬盘是否被占满。&#…

突破边界与持续技术创新,Doris Summit Asia 2023 主论坛亮点解读

峰会官网已上线,最新议程请关注:doris-summit.org.cn Doris Summit 是 Apache Doris 社区一年一度的技术盛会,由 SelectDB 联合 Apache Doris 社区的众多开发者、企业用户和合作伙伴共同发起,专注于传播推广开源 OLAP 与实时数据…

【如何查看Python安装了哪些包】

如何查看Python安装了哪些包 这篇文章主要给大家介绍了关于如何查看Python安装了哪些包的相关资料, Conda是另一种广泛使用的Python包管理工具,它用于安装、管理和升级软件包和其依赖项,需要的朋友可以参考下 目录 查找是否安装了具体的包怎么安装包?更新包总结 c…

C++ 使用Windows的API CreateDirectory 创建多层级文件夹

简介 使用Windows的API创建多层级文件夹 效果 代码 #include <windows.h> #include <direct.h> #include <iostream> #include <string> #include <sstream> #include <vector> //创建多层级文件夹 bool CreateDir(const std:…

web系统接口设计总结

一、前言 在前后端完全分离的开发模式或者说是架构模式下&#xff0c;后端开发者只需要编写后端接口&#xff0c;特别是restful风格接口更为常见。那么暴露给外面的接口大概有三个常见。1、给后台系统调用的接口&#xff0c;2、对客端应用的接口&#xff08;APP或者H5页面&…

Linux文件-内存映射mmap

mmap定义为&#xff1a;Linux通过将一个虚拟内存区域与一个磁盘上的对象(object)关联起来&#xff0c;以初始化这个虚拟内存区域的内容&#xff0c;这个过程称为内存映射(memory mapping)。 在LINUX中我们可以使用mmap用来在进程虚拟内存地址空间中分配地址空间&#xff0c;创…

如何成为CISP信息安全专业人员

随着信息技术和经济社会的交汇融合&#xff0c;网络安全一跃成为国家最为关注的焦点之一。 对于网络安全行业的资质证书来说&#xff0c;CISP成为了目前从业人员最为关注和了解的证书之一&#xff0c;那么&#xff0c;在网络安全行业&#xff0c;CISP证书的价值究竟在哪里&…

MBBF展示的奇迹绿洲:5G的过去、此刻与未来

如果你来迪拜&#xff0c;一定不会错过全世界面积最大的人工岛项目&#xff0c;这是被称为世界第八大奇迹的棕榈岛。多年以来&#xff0c;这座岛从一片砂石、一棵棕榈树开始&#xff0c;逐步建成了整个波斯湾地区的地标&#xff0c;吸引着全世界游人的脚步。 纵观整个移动通信发…

国际前十伦敦金交易app软件最新排行榜(信息汇总)

随着科技的发展&#xff0c;移动交易已成为的趋势。伦敦金交易也不再局限于桌面&#xff0c;而是越来越多地转移到手机上。 为了更好地展现软件的信息&#xff0c;本文将为大家介绍国际前十的伦敦金交易app软件最新排行榜。 1.金荣中国 金荣中国是知名的伦敦金交易平台&…

Maven导入程序包jakarta.servlet,但显示不存在

使用前提&#xff1a;&#xff08;Tomcat10版本&#xff09;已知tomcat10版本之后&#xff0c;使用jakart.servlet。而tomcat9以及之前使用javax.servlet。 问题描述&#xff1a;在maven仓库有导入了Jakarta程序包&#xff0c;但是界面仍然显示是javax。&#xff08;下图&…

基于VCO的OTA稳定性分析的零交叉时差模型研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…