java并发编程死锁定义及如何避免死锁

目录
  • 场景模拟分析
    • 场景一:狭路相逢
    • 场景二:冷战
    • 场景三:哲学家就餐
    • 场景四:竞争资源
  • 死锁是什么?
    • 产生死锁的的四个条件如下:
  • 如何避免死锁?
    • 方案一:破坏不剥夺条件
    • 方案二:破坏请求与保持条件
    • 方案三:破坏循环等待条件
    • 方案四:破坏互斥条件

场景模拟分析

场景一:狭路相逢

在星期天的早上十点半,你在公路上开着车,这是一条窄路,只能容纳一辆车。这时,迎面又驶来一辆车,你们都走到一半,谁也不想倒回去,于是各不相让。陷入无尽的等待。

场景二:冷战

你和她吵架了,谁也不理谁,甚至晚饭时间都各自煮饭。你在炒京酱肉丝,她在做葱烤鲫鱼。炒到一半你发现小葱被她全部拿走了,于是你默默等待她做好菜后再去拿。殊不知她也在等待你炒完菜后来拿酱油。

场景三:哲学家就餐

你和四个好朋友坐在圆形餐桌旁,你们只做两件事情:吃饭,或者思考。吃饭的时候,你们就停止思考。思考的时候,也停止吃饭。每个人面前有一碗兰州炒饭。并且每个人左右两边各有一根筷子。你们必须要拿到两根筷子才能开始吃饭。吃完后再放下筷子,让别人可以使用。吃了一会之后,每个人都拿起了自己左手边的筷子,导致每个人都只有一根筷子,并且等待别人吃完放下筷子给自己。可惜,没有人吃到饭,所以没有人会放下筷子。(著名的哲学家就餐问题)

场景四:竞争资源

你有两个线程 A 和 B ,各自在加锁的状态下运行。 A 持有一部分资源,并且等待 B 线程中的资源以完成自己的工作,而此时 B 线程也在等待 A 中的资源以完成自己的工作。由于他们都是锁定状态,所以他们必须完成了自己的工作后,自己持有的资源才能释放。于是线程无休止的等待,导致死锁。

死锁是什么?

上述四个场景都是程序员在工作或生活中会遇到的问题,人生就像是一个进程,时间是我们的主线程,期间做的每一件事都是开启的一个子线程。当多件事冲突时,并发问题就产生了。以上场景都指向同一类并发问题:死锁。

当两个以上的运算单元,双方都在等待对方停止运行,以获取系统资源,但是没有一方提前退出时,就称为死锁。

产生死锁的的四个条件如下:

1、互斥条件:一个资源每次只能被一个进程使用;

2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;

3、不剥夺条件:进程已获得的资源,在没使用完之前,不能强行剥夺;

4、循环等待条件:多个进程之间形成一种互相循环等待资源的关系。

并发带来压力,有的人或有的程序,会因为承受不住压力而崩溃,情绪崩溃和程序崩溃没什么两样。当然,不论是做人还是写程序,面对问题时,正确的做法都应是采取策略,解除死锁。

如何避免死锁?

死锁一旦发生,便无法解除。我们能做的只能尽量避免死锁。要避免死锁,只需破坏产生死锁的四个条件之一即可。

方案一:破坏不剥夺条件

你想起书中所言:退一步海阔天空。但你也深知公平好过忍让。正值周赛时间,你摇下车窗,对对面的兄弟喊道:咱来比赛一场力扣周赛,谁输了谁倒出去让另一个人过吧!于是你们打开力扣,开始答题。半小时后,你凭借高超的代码水平 AC 了全部题目。对面司机对你拱手道:技不如人,甘拜下风。于是他倒了回去,让出了自己的一半路。最终你们都得以顺利通行。

破坏不剥夺条件:让对面的司机放弃了自己已有的资源。

方案二:破坏请求与保持条件

你在炒菜时发现没有小葱,于是你换位思考,想到她会不会也缺少自己用着的材料。虽然她还在和你冷战,但你劝解自己一个大老爷们不应该和女孩子置气,于是你主动把自己用着的所有材料拿给了她。她感受到你设身处地为她着想,大为感动,你们和好如初。之后她为你们两个人一起炒了京酱肉丝和葱烤鲫鱼。

破坏请求与保持条件:在自己需要的材料缺少时,主动放弃自己持有的资源,防止出现互相等待。

方案三:破坏循环等待条件

你和你的朋友们决定给筷子编上号:1~5。规定每个人拿筷子时必须先拿到自己两边的筷子中号码小的那一根,再去拿号码大的那一根。如果小的那一根没有拿到,不能先拿大的。当你们开始吃饭时,由于数字 5 不可能被一个人单独拿到。因为他旁边的另一根筷子编号必定比 5 小,所以不会再出现每个人都拿着一根的无限等待情形。

破坏循环等待条件:由于筷子指定了编号和获取规则,所以每个锁定状态都将按照顺序执行,于是便杜绝了环路等待条件。

方案四:破坏互斥条件

你在运行两个线程前,预先将线程 A 和 B 中的资源拷贝一份,让他们不需互相等待对方的资源,于是两个线程都得以顺利运行。

破坏互斥条件:由于每次使用时都拷贝一份,所以一个资源可以被多个进程使用。

以上就是java并发编程死锁定义及如何避免死锁的详细内容,更多关于java死锁及避免的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解java中产生死锁的原因及如何避免

    1. Java中导致死锁的原因 Java中死锁最简单的情况是,一个线程T1持有锁L1并且申请获得锁L2,而另一个线程T2持有锁L2并且申请获得锁L1,因为默认的锁申请操作都是阻塞的,所以线程T1和T2永远被阻塞了.导致了死锁.这是最容易理解也是最简单的死锁的形式.但是实际环境中的死锁往往比这个复杂的多.可能会有多个线程形成了一个死锁的环路,比如:线程T1持有锁L1并且申请获得锁L2,而线程T2持有锁L2并且申请获得锁L3,而线程T3持有锁L3并且申请获得锁L1,这样导致了一个锁依赖的环路:T1依

  • java多线程学习之死锁的模拟和避免(实例讲解)

    1.死锁 死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不可能正常终止. Java 死锁产生的四个必要条件: 1.互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用 2.不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放. 3.请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有. 4.循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的

  • java避免死锁的常见方法代码解析

    死锁 索是一个非常有用的工具,运用场景非常多,因为它使用起来非常简单,而且易于理解.但同时它也会带来一些困扰,那就是可能会引起死锁,一旦产生死锁,就会造成系统功能不可用.让我们先来看一段代码,这段代码会引起死锁,使线程 thread_1 和线程 thread_2 互相等待对方释放锁. package thread; public class DeadLockDemo { private static String A = "A"; private static String B = &

  • Java并发编程预防死锁过程详解

    这篇文章主要介绍了Java并发编程预防死锁过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在java并发编程领域已经有技术大咖总结出了发生死锁的条件,只有四个条件都发生时才会出现死锁: 1.互斥,共享资源X和Y只能被一个线程占用 2.占有且等待,线程T1已经取得共享资源X,在等待共享资源Y的时候,不释放共享资源X 3.不可抢占,其他线程不能强行抢占线程T1占有的资源 4.循环等待,线程T1等待线程T2占有的资源,线程T2等待线程T1占有

  • Java中的线程死锁是什么?如何避免?

    认识线程死锁 多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不可能正常终止. 如下图所示,线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态. 下面通过一个例子来说明线程死锁,代码模拟了上图的死锁的情况 (代码来源于<并发编程之美>): public class DeadLockDemo { private static Object resource1 = new Object

  • java并发编程死锁定义及如何避免死锁

    目录 场景模拟分析 场景一:狭路相逢 场景二:冷战 场景三:哲学家就餐 场景四:竞争资源 死锁是什么? 产生死锁的的四个条件如下: 如何避免死锁? 方案一:破坏不剥夺条件 方案二:破坏请求与保持条件 方案三:破坏循环等待条件 方案四:破坏互斥条件 场景模拟分析 场景一:狭路相逢 在星期天的早上十点半,你在公路上开着车,这是一条窄路,只能容纳一辆车.这时,迎面又驶来一辆车,你们都走到一半,谁也不想倒回去,于是各不相让.陷入无尽的等待. 场景二:冷战 你和她吵架了,谁也不理谁,甚至晚饭时间都各自煮饭

  • Java并发编程之死锁相关知识整理

    一.什么是死锁 所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进 二.死锁产生的条件 以下将介绍死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁 互斥条件 进程要求对所分配的资源(如打印机〉进行排他性控制,即在一段时间内某资源仅为一个进程所占有.此时若有其他进程请求该资源,则请求进程只能等待 不可剥夺条件 进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能

  • java并发编程_线程池的使用方法(详解)

    一.任务和执行策略之间的隐性耦合 Executor可以将任务的提交和任务的执行策略解耦 只有任务是同类型的且执行时间差别不大,才能发挥最大性能,否则,如将一些耗时长的任务和耗时短的任务放在一个线程池,除非线程池很大,否则会造成死锁等问题 1.线程饥饿死锁 类似于:将两个任务提交给一个单线程池,且两个任务之间相互依赖,一个任务等待另一个任务,则会发生死锁:表现为池不够 定义:某个任务必须等待池中其他任务的运行结果,有可能发生饥饿死锁 2.线程池大小 注意:线程池的大小还受其他的限制,如其他资源池:

  • 浅谈Java并发编程基础知识

    进程和线程 在并行程序中进程和线程是两个基本的运行单元,在Java并发编程中,并发主要核心在于线程 1. 进程 一个进程有其专属的运行环境,一个进程通常有一套完整.私有的运行时资源:尤其是每个进程都有其专属的内存空间. 通常情况下,进程等同于运行的程序或者应用,然而很多情况下用户看到的一个应用实际上可能是多个进程协作的.为了达到进程通信的目的,主要的操作系统都实现了Inter Process Communication(IPC)资源,例如pipe和sockets,IPC不仅能支持同一个系统中的进

  • java并发编程Lock锁可重入性与公平性分析

    目录 一.相似之处:Lock锁 vs Synchronized 代码块 二.Lock接口中的方法 三.不同点:Lock锁 vs Synchronized 代码块 四.锁的可重入性 4.1. synchronized锁的可重入性 4.2.ReentrantLock可重入锁 五.Lock锁的公平性 一.相似之处:Lock锁 vs Synchronized 代码块 Lock锁是一种类似于synchronized 同步代码块的线程同步机制.从Java 5开始java.util.concurrent.lo

  • Java 并发编程:volatile的使用及其原理解析

    Java并发编程系列[未完]: •Java 并发编程:核心理论 •Java并发编程:Synchronized及其实现原理 •Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) •Java 并发编程:线程间的协作(wait/notify/sleep/yield/join) •Java 并发编程:volatile的使用及其原理 一.volatile的作用 在<Java并发编程:核心理论>一文中,我们已经提到过可见性.有序性及原子性问题,通常情况下我们可以通过Synchroniz

  • Java并发编程之重入锁与读写锁

    重入锁 重入锁,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁.重进入是指任意线程在获取到锁之后能够再次获取该锁而不会被锁阻塞,该特性的实现需要解决以下两个问题. 1.线程再次获取锁.锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取. 2.锁的最终释放.线程重复n次获取了锁,随后在第n次释放该锁后,其他线程能够获取到该锁.锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0时表示锁已经成功释放

  • Java并发编程(CyclicBarrier)实例详解

    Java并发编程(CyclicBarrier)实例详解 前言: 使用JAVA编写并发程序的时候,我们需要仔细去思考一下并发流程的控制,如何让各个线程之间协作完成某项工作.有时候,我们启动N个线程去做一件事情,只有当这N个线程都达到某一个临界点的时候,我们才能继续下面的工作,就是说如果这N个线程中的某一个线程先到达预先定义好的临界点,它必须等待其他N-1线程也到达这个临界点,接下来的工作才能继续,只要这N个线程中有1个线程没有到达所谓的临界点,其他线程就算抢先到达了临界点,也只能等待,只有所有这N

  • Java 并发编程之线程挂起、恢复与终止

    挂起和恢复线程 Thread 的API中包含两个被淘汰的方法,它们用于临时挂起和重启某个线程,这些方法已经被淘汰,因为它们是不安全的,不稳定的.如果在不合适的时候挂起线程(比如,锁定共享资源时),此时便可能会发生死锁条件--其他线程在等待该线程释放锁,但该线程却被挂起了,便会发生死锁.另外,在长时间计算期间挂起线程也可能导致问题. 下面的代码演示了通过休眠来延缓运行,模拟长时间运行的情况,使线程更可能在不适当的时候被挂起: public class DeprecatedSuspendResume

随机推荐