iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Java并发编程中死锁的实现
  • 384
分享到

Java并发编程中死锁的实现

2023-06-15 07:06:45 384人浏览 独家记忆
摘要

这篇文章给大家介绍Java并发编程中死锁的实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、什么是死锁所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进二、死锁产生的

这篇文章给大家介绍Java并发编程中死的实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

一、什么是死锁

所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进

Java并发编程中死锁的实现

二、死锁产生的条件

以下将介绍死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁

互斥条件

进程要求对所分配的资源(如打印机〉进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待

不可剥夺条件

进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)

请求与保持条件

进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放

循环等待条件

存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被链中下一个进程所请求s即存在一个处于等待状态的进程集合{PI, P2,…,, pn}

其中Pi等待的资源被P(i+1)占有( i=0,1,… , n-1),n等待的资源被Po占有

但也有可能Pi等待的资源被P(i+1)占有( i=0,1,… , n-1),但可以通过圈外也获取资源(不死锁),如图所示

Java并发编程中死锁的实现

三、死锁产生的演示

接下来我们创建示例类,通过不同线程来获取不同的锁看看

public class Deadlock implements Runnable {private int flag;//用于区分走向//对象锁 static 使不同线程引用的都是同一地址private static Object obj1 =new Object();//对象锁 static 使不同线程引用的都是同一地址private static Object obj2 =new Object();public Deadlock(int flag) {        this.flag = flag;    }public void run(){if(flag == 1){synchronized (obj1){System.out.println(Thread.currentThread().getName ()+ "获取Obj1,需要请求Obj2");try{Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (obj2){System.out.println(Thread.currentThread().getName ()+ "已获取Obj1、获取Obj2");}}}else{synchronized (obj2){System.out.println(Thread.currentThread().getName ()+ "获取Obj2,需要请求Obj1");try{Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (obj1){System.out.println(Thread.currentThread().getName ()+ "已获取Obj2、获取Obj1");}}}}}

这时我们创建两个线程, 执行这两个obj的锁,看看是否会产生死锁

class DeadlockTest {    public static void main(String[] args) {        Thread thread1 = new Thread(new Deadlock(1),"线程1");        Thread thread2 = new Thread(new Deadlock(2),"线程2");        thread1.start();        thread2.start();    }}//运行结果如下:线程1获取Obj1,需要请求Obj2线程2获取Obj2,需要请求Obj1

我们发现并没有已获取obj1、obj2或者以获取obj2、获取obj1 的输出,因为他们满足了死锁产生的条件

四、死锁的预防

预防死锁是设法至少破坏产生死锁的四个必要条件之一严格的防止死锁的出现

破坏互斥条件

“互斥”条件是无法破坏的。在死锁预防里主要是破坏其他几个必要条件,而不去涉及破坏“互斥”条件

破坏“占有并等待”条件

破坏“占有并等待”条件,就是在系统中不允许进程在已获得某种资源的情况下,申请其他资源

即要想出一个办法,阻止进程在持有资源的同时申请其他资源,有以下思路可提供:

  • 方法一:即创建进程时,要求它申请所需的全部资源,系统或满足其所有要求,或什么也不给它

  • 方法二:要求每个进程提出新的资源申请前,释放它所占有的资源

这样一个进程在需要资源A时,须先把它先前占有的资源R释放掉,然后才能提出对A的申请,即使它可能很快又要用到资源R

破坏“不可抢占”条件

破坏“不可抢占”条件就是允许对资源实行抢夺

如果占有某些资源的一个进程进行下一步资源请求被拒绝,则该进程必须释放它最初占有的资源,如果有必要,可再次请求这些资源和另外的资源

如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。只有在任意两个进程的优先级都不相同的条件下,方法二才能预防死锁

破坏“循环等待”条件

破坏“循环等待”条件的一种方法,是将系统中的所有资源统一编号,进程可在任何时刻提出资源申请,但所有申请必须按照资源的编号顺序(升序)提出。这样做就能保证系统不出现死锁。

五、死锁的避免

死锁的语法是是严格限制产生死锁的条件,避免死锁的方式不严格限制,因为即使死锁的必要条件存在,也不一定发生死锁。而是让程序通过算法再满足条件后避免死锁

避免方法:有序资源分配算法

该算法实现步骤如下:

  • 必须为所有资源统一编号,例如打印机为1、传真机为2、磁盘为3等

  • 同类资源必须一次申请完,例如打印机和传真机一般为同一个机器必须同时申请

  • 不同类资源必须按顺序申请

举例:有两个进程P1和P2,有两个资源R1和R2,P1与P2线程、分别请求资源:R1、R2

P1先获取R1、R2,而P2就请求等待P1释放,这样就破坏了环路条件,避免了死锁的发生

避免方法:银行家算法

银行家算法(Banker's A1Gorithm)是一个避免死锁(Dead1ock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.HE系统设计的一种避免死锁产生的算法

它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。流程图如下:

Java并发编程中死锁的实现

避免方法:顺序加锁

当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生

我们上面的示例代码就是这样的情况,线程1请求Obj1、Obj2,线程2请求Obj2、Obj1

而我们如果能够保证所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生

列如我们线程1请求Obj1、Obj2,线程2请求Obj1、Obj2

按照顺序加锁是一种有效的死锁预防机制。但是这种方式需要事先知道所有可能会用到的锁,但总有些时候是无法预知的,所以该种方式只适合特定场景

避免方法:限时加锁

限时加锁是线程在尝试获取锁的时候加一个超时时间,若超过这个时间则放弃对该锁请求,并回退并释放所有已经获得的锁,然后等待一段随机的时间再重试

以下展示了两个线程以不同的顺序尝试获取相同的两个锁,在发生超时后回很并重试的场景:

//线程 1 锁定AThread 1 locks A//线程 2  锁定BThread 2 locks B//线程 1 尝试去锁定B,但已被锁定Thread 1 attempts to lock 8 but is blocked//线程 2 尝试去锁定A,但已被锁定Thread 2 attempts to lock A but is blocked//线程 1 等待锁定B的时间超时了Thread 1' s lock attempt on B times out//线程 1 进行回退并释放锁定A的资源Thread 1 backs up and releases A as well//线程 1 等待一段时间再重试获取Thread 1 waits randomly (e.g. 257 millis) before retryingThread 2's lock attempt on A times outThread 2 backs up and releases B as wellThread 2 waits randomly (e.g.43 millis) before retrying

在上面的例子中,线程2比线程1早200毫秒进行重试加锁,因此它可以先成功地获取到两个锁,这时线程1尝试获取锁A并且处于等待状态,当线程2结束时,线程1也可以顺利的获得这两个锁

这种方式有两个缺点:

  • 当线程数量少时,该种方式可避免死锁,但当线程数量过多,这些线程的加锁时限相同的概率就高很多,可能会导致超时后重试的死循环

  • Java中不能对synchronized同步块设置超时时间,你需要创建自定义锁或使用Java5中 java .util.concurrent包下的工具

关于java并发编程中死锁的实现就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

--结束END--

本文标题: Java并发编程中死锁的实现

本文链接: https://www.lsjlt.com/news/278810.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java并发编程中死锁的实现
    这篇文章给大家介绍Java并发编程中死锁的实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、什么是死锁所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进二、死锁产生的...
    99+
    2023-06-15
  • java并发编程死锁定义及如何避免死锁
    目录场景模拟分析场景一:狭路相逢场景二:冷战场景三:哲学家就餐场景四:竞争资源死锁是什么?产生死锁的的四个条件如下:如何避免死锁?方案一:破坏不剥夺条件方案二:破坏请求与保持条件方案...
    99+
    2022-11-13
  • java并发编程死锁定义及避免死锁案例分析
    这篇文章主要介绍“java并发编程死锁定义及避免死锁案例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“java并发编程死锁定义及避免死锁案例分析”文章能帮助大家解决问题。场景模拟分析场景一:狭路...
    99+
    2023-06-29
  • 如何通过编程发现Java死锁
    今天就跟大家聊聊有关如何通过编程发现Java死锁,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。死锁是指,两个或多个动作一直在等待其他动作完成而使得所有动作都始终处在阻塞的状态。想要在...
    99+
    2023-06-17
  • Java并发编程之死锁相关知识整理
    目录一、什么是死锁二、死锁产生的条件三、死锁产生的演示四、死锁的预防五、死锁的避免一、什么是死锁 所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都...
    99+
    2022-11-12
  • Go并发编程之死锁与活锁的案例分析
    目录什么是死锁、活锁发生死锁的案例分析发生活锁的案例分析什么是死锁、活锁 什么是死锁:就是在并发程序中,两个或多个线程彼此等待对方完成操作,从而导致它们都被阻塞,并无限期地等待对方完...
    99+
    2023-05-18
    Go死锁 活锁分析 Go 死锁 活锁 Go死锁 Go活锁
  • Java并发之嵌套管程锁死详解
    ·嵌套管程死锁是如何发生的·具体的嵌套管程死锁的例子·嵌套管程死锁 vs 死锁嵌套管程锁死类似于死锁, 下面是一个嵌套管程锁死的场景:Thread 1 synchronizes on AThread 1 synchronizes on B ...
    99+
    2023-05-30
    java 嵌套 并发
  • C#开发中如何处理并发编程和死锁问题
    C#开发中如何处理并发编程和死锁问题,需要具体代码示例摘要:并发编程是现代软件开发中的重要主题,但也带来了一些挑战,例如线程安全、竞态条件和死锁等问题。本文将重点讨论在C#开发中处理并发编程和死锁问题的一些方法,并给出具体的代码示例。引言:...
    99+
    2023-10-22
    并发编程 (Concurrency Programming) 死锁问题 (Deadlock problem) 处理方法
  • 并发编程中如何使用Java中的锁?
    并发编程中如何使用Java中的锁? 在Java中,锁是一种用来控制多个线程访问共享资源的机制。锁可以保证在同一时刻只有一个线程可以访问共享资源,从而避免多个线程同时修改数据导致的数据不一致问题。Java中的锁可以分为两种类型:内置锁和显式锁...
    99+
    2023-08-28
    numy shell 并发
  • Java并发编程中的悲观锁和乐观锁机制
    这篇文章主要介绍“Java并发编程中的悲观锁和乐观锁机制”,在日常操作中,相信很多人在Java并发编程中的悲观锁和乐观锁机制问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java并发编程中的悲观锁和乐观锁机制...
    99+
    2023-06-02
  • Java并发编程ReentrantReadWriteLock加读锁流程
    目录正文属性介绍加锁成功处理正文 protected final int tryAcquireShared(int unused) { Thread current = Th...
    99+
    2023-05-19
    Java并发ReentrantReadWriteLock Java并发加读锁
  • Java并发编程之StampedLock锁介绍
    StampedLock: StampedLock是并发包里面JDK8版本新增的一个锁,该锁提供了三种模式的读写控制,当调用获取锁的系列函数时,会返回一个long 型的变量,我们称之为...
    99+
    2022-11-13
  • Java并发中死锁、活锁和饥饿是什么意思
    解答 死锁是指两个或者两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,他们将无法推进下去。 如果线程的智力不够, 且都秉承着“谦让”的原则,...
    99+
    2022-11-12
  • Java中死锁与活锁的具体实现
    目录活锁与死锁活锁死锁死锁的四个必要条件互斥条件请求和保持条件不剥夺条件环路等待条件死锁示例死锁排查总结一下如何避免死锁预防死锁设置加锁顺序活锁示例解决活锁活锁与死锁 活锁 活锁同样...
    99+
    2022-11-13
  • 如何在并发编程中避免死锁和饥饿问题?
    在并发编程中,死锁和饥饿问题是非常常见的。死锁指的是两个或多个线程互相等待对方释放资源,导致所有线程都无法继续执行的情况。饥饿问题则是指某个线程由于优先级低或资源不足而无法获得所需资源,一直处于等待状态。 为了避免死锁和饥饿问题,我们可以采...
    99+
    2023-07-23
    bash leetcode 并发
  • Java并发编程的悲观锁和乐观锁机制
    本篇内容主要讲解“Java并发编程的悲观锁和乐观锁机制”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java并发编程的悲观锁和乐观锁机制”吧!一、资源和加锁1、场景描述多线程并发访问同一个资源问...
    99+
    2023-06-16
  • java并发编程中ReentrantLock可重入读写锁
    目录一、ReentrantLock可重入锁二、ReentrantReadWriteLock读写锁三、读锁之间不互斥一、ReentrantLock可重入锁 可重入锁ReentrantL...
    99+
    2022-11-13
  • Java如何实现并发编程?
    Java如何实现并发编程? 在今天的软件开发领域中,多核处理器已经成为了主流。因此,实现并发编程已经成为了必要的技能。Java是一种支持并发编程的编程语言,它提供了一些重要的工具和API来帮助开发人员实现并发编程。本文将介绍Java中实现并...
    99+
    2023-08-28
    numy shell 并发
  • JUC并发编程中的锁有哪些
    这篇文章主要讲解了“JUC并发编程中的锁有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JUC并发编程中的锁有哪些”吧!当多个线程访问一个对象时,如果不用考虑这些线程在运行环境下的调度和...
    99+
    2023-06-22
  • Java并发编程之StampedLock锁怎么应用
    本篇内容介绍了“Java并发编程之StampedLock锁怎么应用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!StampedLock:St...
    99+
    2023-06-30
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作