Java多线程之死锁(死锁产生条件、手写简单死锁程序、破坏死锁)(面试常有)

目录

一、死锁。

(1)实际生活"死锁"情景。

(2)程序中举例。

(3)死锁产生必要的条件。

<1> 互斥使用。

<2> 不可抢占。

<3> 请求和保持。

<4> 循环等待。

(4)避免死锁。

二、IDEA中写简单"死锁程序"。

<0>分析与解释。

<1>简单死锁程序(类DeadLockDemo)

<2>测试类(Test)

<3>程序执行结果。(发生"死锁")

<4>破坏上面的"简单死锁程序"。

(I)破坏互斥条件。

(II)破坏不可抢占条件。

(III)破坏请求和保持条件。

(IIII)破坏循环等待条件。

三、总结

(1)关于死锁。


一、死锁。

(1)实际生活"死锁"情景。
  • 有这样一个场景:一个中国人和一个美国人在一起吃饭。
  • 其中美国人拿了中国人的筷子,中国人拿了美国人的刀叉,于是两个人开始争执不休。
  • 中国人:”你先给我筷子,我再给你刀叉!
  • 美国人:“你先给我刀叉,我再给你筷子!
  • .......

结果可想而知,两个人都吃不成饭...


  • 这个例子中的中国人和美国人相当于不同的"线程",而筷子和刀叉就相当于"锁"。而两个线程在运行的时候都在等待对方的"锁",这样就造成了程序的停滞。
  • 这种现象被称为"死锁"。
(2)程序中举例。
  • 有两个线程。thread01、thread02。
  • thread01:a锁——>b锁thread02:b锁——>a锁
  • thread01获取完a锁,执行完毕后不释放a锁,接着thread01又去获取b锁。
  • 而thread02获取完b锁,执行完毕后不释放b锁,接着thread02有去获取a锁。
  • 两个线程同时去执行,就会造成"死锁"情况。
(3)死锁产生必要的条件。
<1> 互斥使用。
  • 互斥(排它性)。即当资源被一个线程使用(占有)时,别的线程不能使用。
  • 像同步代码块、同步方法一样,拿到"锁"时,其它线程不能再进去访问或使用
<2> 不可抢占。
  • 资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
  • 也就是拿到这个线程后,另外的线程不能抢"锁"
  • 如果各个线程可以"抢锁",就算前面抢到"锁"的线程因为某种原因无法释放"锁",后面等待的线程也可以去抢到"锁",也就不会造成阻塞(死锁)。
<3> 请求和保持。
  • 即当资源请求者在请求其他的资源的同时保持对原有资源的占用
  • 如上的两个线程"thread01"、"thread02"。thread01拿到a锁,用完就释放掉,而thread02拿到b锁,用完也释放掉。这样再互相拿自己需要的"锁",就不会造成"死锁"现象。
<4> 循环等待。
  • 即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
  • 而上面的例子也是一个小等待队列(环)。thread01->a->b->thread02->b->a。
  • 如果改成thread01:a锁——>b锁thread02:a锁——>b锁。也不会造成死锁的情况了。

注意上述的四个条件都满足,才会造成"死锁"的产生。

(4)避免死锁。
  • 在实际开发中,为了避免"死锁"的发生,只需要把上述四个条件中的任意一个打破,就可以避免"死锁"的现象产生

二、IDEA中写简单"死锁程序"。

也就是整个程序都满足上述的四个条件

<0>分析与解释。
  • "死锁类"不采用实现Runnable接口,重新run()方法。而是在测试中直接使用匿名的Runnable实现子类。()->{}。中括号里面就是实现的run()方法
  • "死锁类"创建的两个类的锁对象(static。在该"死锁"类的new两个即可。保证a与b"锁"是这个"死锁类"是共享的。


  • 测试类中到时候模拟两个线程,同时new两个"死锁"类的对象。d1、d2是不共享的,但是锁a、锁b是共享的资源。


  • 测试类中的new Thread(Runnable target)。参数内部是使用Lambda表达式(也可以使用匿名内部类)也就是在重新的run()方法里面进行调用方法操作(d1.执行死锁方法、d2.执行死锁方法)

  • 测试类中最后两个线程分别去使用start()方法。然后分别去拿各自的"锁a"、"锁b",然后阻塞(哈哈哈!)

  • "死锁类"中这里注意还需要有一个布尔类型的变量。去控制获取锁的顺序。顺序????就是为"true"时控制一个线程拿"锁"时,从a锁——>b锁。值为false时让另外一个线程拿"锁"时,从b锁——>a锁。flag不是设置成共享的(不是static)。

(具体详细代码如下。)

<1>简单死锁程序(类DeadLockDemo)
package com.fs;/*** @Title: DeadLockDemo* @Author HeYouLong* @Package com.fs* @Date 2024/10/12 下午8:41* @description: 简单死锁程序演示*/
public class DeadLockDemo {//锁a与锁bprivate static Object a = new Object();private static Object b = new Object();//控制拿锁的顺序,a——>b或者b——>aprivate boolean flag;//提供构造方法改布尔值public DeadLockDemo(boolean flag) {this.flag = flag;}public void testDeadLock() throws InterruptedException {if(flag){//a——>bsynchronized (a){System.out.println(Thread.currentThread().getName()+"执行a锁代码块的资源");Thread.sleep(100); //模拟执行完后等待synchronized (b){System.out.println(Thread.currentThread().getName()+"执行b锁代码块的资源");Thread.sleep(100); //模拟执行完后等待}}}else {//b——>asynchronized (b){System.out.println(Thread.currentThread().getName()+"执行b锁代码块的资源");Thread.sleep(100); //模拟执行完后等待synchronized (a){System.out.println(Thread.currentThread().getName()+"执行a锁代码块的资源");Thread.sleep(100); //模拟执行完后等待}}}}
}
<2>测试类(Test)
package com.fs;
/*** @Title: Test* @Author HeYouLong* @Package com.fs* @Date 2024/10/13 上午10:59* @description: 测试类*/
public class Test {public static void main(String[] args) {//创建不同对象DeadLockDemo d1 = new DeadLockDemo(true);DeadLockDemo d2 = new DeadLockDemo(false);Thread t1 = new Thread(()->{//线程t1的run()方法使用d1对象//但是在对象调用testDeadLock()使用的是共享资源的锁try {d1.testDeadLock();} catch (InterruptedException e) {throw new RuntimeException(e);}},"线程1");Thread t2 = new Thread(()->{//线程t2的run()方法使用d2对象// 但是在对象调用testDeadLock()使用的是共享资源的锁try {d2.testDeadLock();} catch (InterruptedException e) {throw new RuntimeException(e);}},"线程2");//启动线程t1.start();t2.start();}
}
<3>程序执行结果。(发生"死锁")

<4>破坏上面的"简单死锁程序"。
(I)破坏互斥条件。
(II)破坏不可抢占条件。
(III)破坏请求和保持条件。
  • 让两个线程"t1"、"t2"都执行完资源后释放完各自的"锁",然后再去申请其它"锁"。(不允许它保持
public void testDeadLock() throws InterruptedException {if(flag){//a——>bsynchronized (a){System.out.println(Thread.currentThread().getName()+"执行a锁代码块的资源");Thread.sleep(100); //模拟执行完后等待}synchronized (b){System.out.println(Thread.currentThread().getName()+"执行b锁代码块的资源");Thread.sleep(100); //模拟执行完后等待}}else {//b——>asynchronized (b){System.out.println(Thread.currentThread().getName()+"执行b锁代码块的资源");Thread.sleep(100); //模拟执行完后等待}synchronized (a){System.out.println(Thread.currentThread().getName()+"执行a锁代码块的资源");Thread.sleep(100); //模拟执行完后等待}}}

(IIII)破坏循环等待条件。
  • 简单修改即可。不让他们请求锁时形成环路。(把顺序都变成"锁a"——>"锁b"

三、总结

(1)关于死锁。
  • "死锁"现象造成,必须四个条件都满足了。只要破坏其中一个条件,"死锁"的现象就不存在了。
  • 以后写代码,尽量让加锁的顺序保持一致。或者某个线程操作多个锁,操作完成之后,要让它释放掉。
  • 在实际开发中,只需要把上述四个条件任意一个打破,就可以最大可能的避免死锁。

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

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

相关文章

iOS 14 自定义画中画悬浮窗 Custom AVPictureInPictureController 实现方案

iOS 14&#xff0c;基于 AVPictureInPictureController&#xff0c;实现自定义画中画&#xff0c;涵盖所有功能与难点。 市面上的各种悬浮钟和提词器的原理都是基于此。 Demo源码在文末。 使用 iOS 画中画的要求&#xff1a; 真机&#xff0c;不能使用模拟器&#xff1b;iO…

starrocks-删除表字段

1、背景 之前做了个大宽表&#xff0c;将近100个字段&#xff0c;但是后来发现很多字段在实际生产上都没有用到&#xff0c;并且随着数据量的增加&#xff0c;给集群的存储以及消费任务的解析带来了比较大的压力。所以决定对字段做删除处理。 当前的表是使用routine load任务从…

hadoop全分布式搭建(三台虚拟机,一个主节点,两个从节点)

根据尚硅谷哔哩哔哩视频搭建&#xff1a;bilibili.com/video/BV1Qp4y1n7EN/ 安装虚拟机教程可参考&#xff1a;VMware虚拟机 安装 Centos7(linux)&#xff08;新手超详细教程&#xff09;_vmware安装centos7教程-CSDN博客 集群配置如下&#xff1a; 一、先配置一台虚拟机hadoo…

【计算机网络 - 基础问题】每日 3 题(三十八)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

【华为HCIP实战课程七】OSPF邻居关系排错MTU问题,网络工程师

一、MTU MUT默认1500,最大传输单元,一致性检测 [R3-GigabitEthernet0/0/1]mtu 1503//更改R3的MTU为1503 查看R3和SW1之间的OSPF邻居关系正常: 默认华为设备没有开启MTU一致性检测! [R3-GigabitEthernet0/0/1]ospf mtu-enable //手动开启MTU检测 [SW1-Vlanif30]ospf mtu…

PCL点云处理之求法向量

求法向量干什么&#xff1f;将点渲染成面 1、一个点垂直于一个曲线的切线叫法线 2、在点云中取一块区域&#xff0c;用最小二乘将区域中的点云拟合成一个面&#xff08;贴合在曲面上的一个切面&#xff09;在相近的区域计算出n个这样的面&#xff0c;用这个面求出法向量&#…

第十五届蓝桥杯C++B组省赛

文章目录 1.握手问题解题思路1&#xff08;组合数学&#xff09;解题思路2&#xff08;暴力枚举&#xff09; 2.小球反弹做题思路 3.好数算法思路&#xff08;暴力解法&#xff09;---不会超时 4.R格式算法思路 5.宝石组合算法思路---唯一分解定理 6.数字接龙算法思路----DFS 7…

分布式数据库的进度管理:TiDB 备份恢复工具 PiTR 的原理与实践

导读 对于一款企业级数据库产品而言&#xff0c;数据的安全性和可恢复性是至关重要的。PiTR&#xff08;Point in Time Restore&#xff09;作为 TiDB 备份工具的核心功能之一&#xff0c;提供了一种精细的数据恢复能力&#xff0c;允许用户将数据库集群恢复到过去的任意时间点…

C语言 | 第十六章 | 共用体 家庭收支软件-1

P 151 结构体定义三种形式 2023/3/15 一、创建结构体和结构体变量 方式1-先定义结构体&#xff0c;然后再创建结构体变量。 struct Stu{ char *name; //姓名 int num; //学号 int age; //年龄 char group; //所在学习小组 float score; //成绩 }; struct Stu stu1, stu2; //…

基于SpringBoot+Vue+Uniapp的植物园管理小程序系统(2024最新,源码+文档+远程部署+讲解视频等)

3. 论文参考 4. 项目运行截图 5. 技术框架 5.1 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring …

Spring Boot在知识管理中的应用

1系统概述 1.1 研究背景 如今互联网高速发展&#xff0c;网络遍布全球&#xff0c;通过互联网发布的消息能快而方便的传播到世界每个角落&#xff0c;并且互联网上能传播的信息也很广&#xff0c;比如文字、图片、声音、视频等。从而&#xff0c;这种种好处使得互联网成了信息传…

数据检测和响应:DDR 用于数据安全

数据检测和响应 (DDR) 用于主动数据安全态势管理 企业必须保护其数据免受网络攻击&#xff0c;主要有三个原因&#xff1a; 1. 公司有法律义务保证客户信息的安全&#xff1b; 2. 不这样做会损害公司的声誉&#xff1b; 3. 补救数据泄露的影响可能代价高昂&#xff0c;而且…

数据结构前置知识(上)

1. 初识集合框架 1.1 什么是集合框架 在了解集合框架之前,我们先来认识一下数据结构,所谓数据结构就是描述和组织数据的一个东西. 那什么是集合框架呢?在java里面集合框架(Java Collection Framework),又被称为容器container,说白了就是很多个接口,抽象类,实现类组成的一个包,…

架构设计笔记-12-信息系统架构设计理论与实践

目录 知识要点 案例分析 1.Java企业级应用系统 2.c/s架构&#xff0c;b/s架构 知识要点 软件架构风格是描述某一特定应用领域中系统组织方式的惯用模式。架构风格定义了一类架构所共有的特征&#xff0c;主要包括架构定义、架构词汇表和架构约束。 数据挖掘是从数据库的大…

OceanBase 4.x 部署实践:如何从单机扩展至分布式部署

OceanBase 4.x 版本支持2种部署模式&#xff1a;单机部署与分布式部署&#xff0c;同时支持从单机平滑扩展至分布式架构。这样&#xff0c;可以有效解决小型业务向大型业务转型时面临的扩展难题&#xff0c;降低了机器资源的成本。 以下将详述如何通过命令行&#xff0c;实现集…

解决IPv6网络引起的网页与程序卡顿问题-本地DNS解析方案

一、问题环境 连接IPv6WiFi网络时&#xff0c;易出现网页打不开&#xff0c;程序开启无法加载画面。系统环境为Win10。 二、解决思路 在用户端无法触及路由器、网关等管理资源时&#xff0c;只能从本地环境中更改配置。多适用于公共WiFi&#xff0c;私人WiFi可直接从路由器DNS、…

手撕数据结构 —— 队列(C语言讲解)

目录 1.什么是队列 2.如何实现队列 3.队列的实现 Queue.h中接口总览 具体实现 结构的定义 初始化 销毁 入队列 出队列 取队头元素 取队尾元素 判断是否为空 获取队列的大小 4.完整代码附录 Queue.h Queue.c 1.什么是队列 队列是一种特殊的线性表&#xff0…

【uni-app】HBuilderX安装uni-ui组件

目录 1、官网找到入口 2、登录帐号 3、打开HuilderX 4、选择要应用的项目 5、查看是否安装完成 6、按需安装 7、安装完毕要重启 8、应用 前言&#xff1a;uniapp项目使用uni-ui组件方式很多&#xff0c;有npm安装等&#xff0c;或直接创建uni-ui项目&#xff0c;使用un…

【Oracle数据库进阶】001.SQL基础查询_查询语句

课 程 推 荐我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448;入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448;虚 拟 环 境 搭 建 &#xff1a;&#x1…

Aria2Cloudreve任意文件写入到RCE

什么是Aria2 Aria2 是一个轻量级的命令行下载工具&#xff0c;支持多种下载协议&#xff0c;如 HTTP、FTP、SFTP、BitTorrent 和 Metalink。它以其强大的多源下载能力而著称&#xff0c;可以同时从多个服务器或对等节点下载文件&#xff0c;加快下载速度。Aria2 占用资源少&am…