产生死锁的四个必要条件

产生死锁的四个必要条件

  1. 互斥使用: 一个资源每次只能被一个线程使用。这意味着如果一个线程已经获取了某个资源(比如锁),那么其他线程就必须等待,直到该线程释放资源。

  2. 不可抢占: 已经获得资源的线程在释放资源之前,不能被其他线程抢占。只有拥有资源的线程自己能够释放资源,其他线程无法将其强行抢占。

  3. 请求保持: 一个线程在持有至少一个资源的情况下,又请求获取其他资源。这样的情况下,如果其他资源被其他线程持有并且不释放,就会导致请求线程等待,从而可能形成死锁。

  4. 循环等待: 存在一组等待进程 {P1, P2, ..., Pn},其中P1等待P2持有的资源,P2等待P3持有的资源,...,Pn等待P1持有的资源。这样的循环等待条件是死锁的充分条件

注意 以上是必要条件 在数学中 分必要条件 充要条件等 必要条件是四个缺一不可的 

也就是说 要产生死锁 这些条件是不可或缺的

以上四个必要条件分别用java代码解释说明

目录

互斥使用

不可抢占

请求保持

循环等待


互斥使用

互斥是指在多任务处理中,对共享资源的访问进行限制,确保同一时刻只有一个任务(或线程)能够访问共享资源。这种限制保证了对共享资源的安全访问,避免了数据竞争和数据不一致的问题。

在并发编程中,互斥通常通过锁(如Java中的`synchronized`关键字或`Lock`接口)来实现。当一个任务需要访问共享资源时,它会尝试获取锁,如果锁已被其他任务持有,则该任务会被阻塞,直到锁被释放。一旦任务获取到锁,它就可以安全地访问共享资源,在完成操作后释放锁,以便其他任务可以继续访问。

函数起名根据: 

public static void criticalSection1() {System.out.println(Thread.currentThread().getName() + "进入临界区");System.out.println(Thread.currentThread().getName() + "离开临界区");}public static void main(String[] args) {new Thread(()->{criticalSection1();}).start();new Thread(()->{criticalSection1();}).start();}

对于这段代码 会有这样一个执行结果 因为是并发执行的

可以看到 在进程1进入临界区的时候 0也能进入临界区

接下来我们加上一段锁

private static final Object lock = new Object();public static void criticalSection() {synchronized(lock) {System.out.println(Thread.currentThread().getName() + "进入临界区");// 这里是临界区,只有一个线程可以执行这段代码System.out.println(Thread.currentThread().getName() + "离开临界区");}}public static void main(String[] args) {new Thread(()->{criticalSection();}).start();new Thread(()->{criticalSection();}).start();}

对于这段代码  只有这一一种执行结果 因为每次只有一个线程能够进入临界区执行代码,确保了临界区内的操作不会被并发执行,从而避免了数据竞争和数据不一致的问题。 表现了互斥等到(两个或多个线程同时想要获取一个资源 但是只能等到另一个释放)

不可抢占

public class Main3 {private static final Object lock = new Object();public static void main(String[] args) {// 线程1获取锁并执行耗时操作new Thread(() -> {try {// 等待2启动,保证2在1之后获取锁Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}synchronized(lock) {System.out.println("线程1获得了锁");try {// 模拟耗时操作Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程1释放了锁");}}).start();// 线程2尝试获取锁new Thread(() -> {try {// 等待一段时间,模拟线程2稍晚启动Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized(lock) {// 线程2无法获取锁,因为锁已被线程1持有System.out.println("线程2获得了锁");}System.out.println("线程2释放了锁");}).start();}
}

以上代码有两种执行结果

线程2获得了锁
线程2释放了锁
线程1获得了锁
线程1释放了锁
线程1获得了锁
线程1释放了锁
线程2获得了锁
线程2释放了锁

而没有 1获得了锁下一句是2释放了锁 这种情况

这就表现不可抢占的特性,即已经获得资源的线程在释放资源之前,不能被其他线程抢占。

请求保持

先想一下这段话:  一个线程在持有至少一个资源的情况下,又请求获取其他资源。这样的情况下,如果其他资源被其他线程持有并且不释放,就会导致请求线程等待,从而可能形成死锁。

我们可以理解为 

t1线程 在持有lock资源的情况下,又请求获取lock2资源。这样的情况下,如果lock2资源被t2线程持有并且不释放,就会导致请求线程等待,从而可能形成死锁。

public class Main4 {private static Object lock = new Object();private static Object lock2 = new Object();public static void main(String[] args) {Thread t1 = new Thread(()-> {synchronized (lock) {System.out.println("t1获得lock");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (lock2) {System.out.println("t1获得lock2");}}});Thread t2 = new Thread(()->{synchronized (lock2) {System.out.println("t2获得lock2");while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});t1.start();t2.start();}
}

可以观察到 t2不释放lock2 t1就不能拿到lock2

以上表现出 请求保持是死锁的一个必要条件之一,指的是一个线程在持有至少一个资源的情况下,又请求获取其他资源,但这些资源已被其他线程持有并且不释放,从而导致请求线程等待,可能形成死锁。

循环等待

也就是哲学家进餐问题

public class Main5 {private static final Object resource1 = new Object();private static final Object resource2 = new Object();public static void main(String[] args) {// 线程1持有资源1,请求资源2Thread t1 = new Thread(() -> {synchronized (resource1) {System.out.println("线程1持有资源1");try {Thread.sleep(1000); // 为了确保线程2先持有资源2} catch (InterruptedException e) {e.printStackTrace();}synchronized (resource2) {System.out.println("线程1持有资源2");}}});// 线程2持有资源2,请求资源1Thread t2 = new Thread(() -> {synchronized (resource2) {System.out.println("线程2持有资源2");synchronized (resource1) {System.out.println("线程2持有资源1");}}});t1.start();t2.start();}
}

导致了循环等待 也就是 存在一组等待进程 {P1, P2},其中P1等待P2持有的资源,P2等待P1持有的资源

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

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

相关文章

[尚硅谷flink] 检查点笔记

在Flink中,有一套完整的容错机制来保证故障后的恢复,其中最重要的就是检查点。 文章目录 11.1 检查点11.1.1 检查点的保存1)周期性的触发保存2)保存的时间点3)保存的具体流程 11.1.2 从检查点恢复状态11.1.3 检查点算法…

如何在Windows安装LocalSend并结合内网穿透实现公网跨平台远程文件互传

文章目录 1. 在Windows上安装LocalSend2. 安装Cpolar内网穿透3. 公网访问LocalSend4. 固定LocalSend公网地址 本篇文章介绍在Windows中部署开源免费文件传输工具——LocalSend,并且结合cpolar内网穿透实现公网远程下载传输文件。 localsend是一款基于局域网的文件传…

【菜狗学前端】原生Ajax笔记(包含原生ajax的get/post传参方式、返回数据等)

这回图片少,给手动替换了~祝看得愉快,学的顺畅!哈哈 一 原生ajax经典四步 (一) 原生ajax经典四步 第一步:创建网络请求的AJAX对象(使用XMLHttpRequest) JavaScript let xhr new XMLHttpRequest() 第二…

【C语言】简易版扫雷+进阶版扫雷

目录 前言 一、分模块化 二、准备雷盘 2.1 游戏菜单 2.2 创建雷盘思路 2.3 构建雷盘 2.4 雷盘展示 2.4.1 初始化雷盘 2.4.2 打印雷盘 三、排雷 3.1 布置雷 3.2 排查雷 四、进阶版扫雷 总结 前言 C语言实现扫雷小游戏,帮我们更进一步的掌握数组、模块化…

bugku-web-decrypt

这里的提示解密后没有什么意义 这里下载文件包 得到一个index.php文件 得到代码 <?php function encrypt($data,$key) {$key md5(ISCC);$x 0;$len strlen($data);$klen strlen($key);for ($i0; $i < $len; $i) { if ($x $klen){$x 0;}$char . $key[$x];$x1;}for…

鸿蒙开发快速入门

基本概念 ArkTS 因为ArkTS是基于Type Script扩展而来&#xff0c;是Type Script的超集&#xff0c;所以也可以关注一下Type Script的语法来理解ArkTS的语法 ArkUI HarmonyOS提供了一套UI开发框架&#xff0c;即方舟开发框架&#xff08;ArkUI框架&#xff09;。方舟开发框架…

k8s:kubectl 命令设置简写启用自动补全功能

k8s&#xff1a;kubectl 命令设置简写&启用自动补全功能 1、设置kubectl命令简写2、启用kubectl自动补全功能 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; Kubernetes&#xff08;K8s&#xff09;是一个强大的容器编排平台&#xff0…

MES管理系统在人工智能方面的应用

为了加强生产管理&#xff0c;提升企业管理水平&#xff0c;制造业之中的很多企业都运用的MES生产管理系统&#xff0c;借以提高对生产车间的监管。那么&#xff0c;MES系统应用的哪些技术&#xff0c;可以促使生产管理变得简单呢?其核心技术主要有以下几个方面。 1、过程控制…

Linux配置程序后台运行(前后台来回切换)

Linux配置程序后台运行 在日常开发过程中&#xff0c;会遇到我们在前台运行程序&#xff0c;此时我们临时有事&#xff0c;但不能关闭终端&#xff0c;否则程序就会在电脑熄屏&#xff08;终端session断开后&#xff09;停止运行。 那么作为一个合格的开发&#xff0c;就必须要…

LeetCode刷题记(三):61~90题

61. 旋转链表 给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k 2 输出&#xff1a;[4,5,1,2,3]示例 2&#xff1a; 输入&#xff1a;head [0,1,2], k 4 输出&…

今天掏心窝子!聊聊35岁了程序员何去何从?

今天的内容不聊技术&#xff0c;聊聊轻松的话题&#xff0c;脑子高速转了好几周&#xff0c;停下来思考一下人生…… 不对&#xff0c;关于35岁的问题好像也不轻松&#xff0c;些许有点沉重&#xff0c;反正不是技术&#xff0c;不用高速转动脑细胞了&#xff0c;哈哈。 兄弟…

未来已来,一键解锁AI秘境:全能型人工智能技术网站大揭秘(一键收藏)

1、KKAI&#xff08;kk.zlrxjh.t op&#xff09; KKAI是一个融合了星火大模型和文心大模型技术的知识增强型大语言模型&#xff0c;主要针对自然语言处理&#xff08;NLP&#xff09;的技术开发与研究。 该模型展现出卓越的语义理解与生成功能&#xff0c;能有效处理多样的自然…