死锁的成因, 和解决方案.

2024-04-13 21:28
文章标签 解决方案 死锁 成因

本文主要是介绍死锁的成因, 和解决方案.,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

死锁

死锁就是两个或两个以上线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

成因

1.一个线程一把锁

一个线程,对同一个对象,重复加锁两次,如果不支持可重入,即会出现死锁现象,但是在 Java 中,synchronized 和 ReentarntLock(后面讲) 都是支持可重入的!

所以在 Java 中,也就不会出现这样的情况,但不排除在其他语言会出现这种情况。

2.两个线程两把锁

 
public static void main(String[] args) {Object knife = new Object(); //刀Object fork = new Object(); //叉Thread t1 = new Thread(() -> {synchronized (knife) {System.out.println("张三拿到刀了!");synchronized (fork) {System.out.println("张三刀和叉都拿到了!吃牛排!");}}});Thread t2 = new Thread(() -> {synchronized (fork) {System.out.println("小美拿到叉了!");synchronized (knife) {System.out.println("小美刀和叉都拿到了!吃牛排!");}}});t1.start();t2.start();
}

此时就发现,代码僵住了,其实也就是 t1 在等 t2 释放锁,而 t2 也在等 t1 释放锁,此时两个线程都无休止的阻塞等待下去了,最终导致,张三拿不到刀叉,小美也拿不到刀叉!都不吃成牛排了! 

3.多个线程多把锁

哲学家就餐问题

有一个桌子,围着一圈哲学家,每个哲学家面前放着一碗面,哲学家两两之间放一只筷子,而桌子上的哲学家只会做两件事:吃面(获取到锁,执行后续代码)或者思考人生(阻塞等待)。

当哲学家吃面的时候,就会拿起左右手的筷子(先拿左边,再拿右边),当哲学家思考人生的时候,就会放下左右手的筷子。

如果哲学家拿到两根筷子了,就会吃面,没拿到就会思考人生!

极端情况来了!如果五个哲学家同时都拿起左手边的筷子,接着每个人都去拿自己右手边的筷子,发现右边的筷子都被别人拿走了!都要等右边的哲学家把筷子放下,此时就僵住了!由于哲学家们互不相让,此时也就形成了死锁的现象。

①互斥条件:一个资源只能被一个线程占有,当这个资源被占用后其他线程就只能等待。

②不可剥夺条件:当一个线程不主动释放资源时,此资源一直被拥有线程占有。

③请求并持有条件:线程已经拥有一个资源后仍然不满足,又尝试请求新的资源。

④环路等待条件:产生死锁一定是发生了线程资源环路链。

解决

改变死锁中的任意一个或多个条件就可以解决死锁问题,其中被修改的条件只有后两个:请求并持有条件和环路等待条件。

修改请求并持有条件

:获得了一把锁之后不再去请求获取另一把锁

 

  打破循环

于哲学家吃面的问题,对每根筷子进行编号,约定好,只能先拿左右手编号小的筷子,再拿编号大的筷子。

此时这样一来,总有一个人拿不到筷子,那么上述情况,拿到编号为 4 筷子的哲学家就能拿编号为 5 筷子吃面了,吃完了放下两支筷子,接着右手边拿到 3 筷子的哲学家就拿起放下的 编号4 筷子进行吃面了,以此类推.....

本质上我们这里讲的避免死锁的方案,就是约定加锁顺序!约定顺序后,死锁的问题就解决了!也就打破了第四点的循环等待!

其实还有一种算法,银行家算法, 但实际开发中不推荐使用,比起上述讲的办法银行家算法更复杂,也更容易出错,所以更推荐上述约定顺序的方法!

 

这篇关于死锁的成因, 和解决方案.的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/901259

相关文章

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi

使用DrissionPage控制360浏览器的完美解决方案

《使用DrissionPage控制360浏览器的完美解决方案》在网页自动化领域,经常遇到需要保持登录状态、保留Cookie等场景,今天要分享的方案可以完美解决这个问题:使用DrissionPage直接... 目录完整代码引言为什么要使用已有用户数据?核心代码实现1. 导入必要模块2. 关键配置(重点!)3.

Jackson库进行JSON 序列化时遇到了无限递归(Infinite Recursion)的问题及解决方案

《Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursion)的问题及解决方案》使用Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursi... 目录解决方案‌1. 使用 @jsonIgnore 忽略一个方向的引用2. 使用 @JsonManagedR

Seata之分布式事务问题及解决方案

《Seata之分布式事务问题及解决方案》:本文主要介绍Seata之分布式事务问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Seata–分布式事务解决方案简介同类产品对比环境搭建1.微服务2.SQL3.seata-server4.微服务配置事务模式1

关于Nginx跨域问题及解决方案(CORS)

《关于Nginx跨域问题及解决方案(CORS)》文章主要介绍了跨域资源共享(CORS)机制及其在现代Web开发中的重要性,通过Nginx,可以简单地解决跨域问题,适合新手学习和应用,文章详细讲解了CO... 目录一、概述二、什么是 CORS?三、常见的跨域场景四、Nginx 如何解决 CORS 问题?五、基

Nginx启动失败:端口80被占用问题的解决方案

《Nginx启动失败:端口80被占用问题的解决方案》在Linux服务器上部署Nginx时,可能会遇到Nginx启动失败的情况,尤其是错误提示bind()to0.0.0.0:80failed,这种问题通... 目录引言问题描述问题分析解决方案1. 检查占用端口 80 的进程使用 netstat 命令使用 ss