20.线程的活性故障:死锁

2023-12-20 20:58
文章标签 线程 死锁 故障 20 活性

本文主要是介绍20.线程的活性故障:死锁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 1.定义
  • 2.死锁产生的条件
  • 3.规避死锁的方法
  • 4.死锁的恢复

1.定义

死锁是线程的一种常见活性故障。如果两个或者更多的线程因相互等待对方而被永远暂停(线程的生命周期状态为 BLOCKED 或者 WAITING), 那么我们就称这些线程产生了死锁(Deadlock)。 由于产生死锁的线程的生命周期状态永远是非运行状态,因此这些线程所要执行的任务也永远无法进展。死锁产生的一种典型情形如下图。
在这里插入图片描述

2.死锁产生的条件

线程一旦产生死锁,那么这些线程及相关的资源将满足如下全部条件。

  • 资源互斥。涉及的资源必须是独占的,即每个资源一次只能够被一个线程使用。
  • 资源不可抢夺。涉及的资源只能够被其持有者(线程)主动释放,而无法被资源的持有者和申请者之外的第三方线程所抢夺(被动释放)。
  • 占用并等待资源。涉及的线程当前至少持有一个资源(资源 A)并申请其他资源(资源B),而这些资源(资源 B) 恰好被其他线程持有 。 在这个资源等待的过程中,线程并不释放其已经持有的资源 。
  • 循环等待资源。涉及的线程必须在等待别的线程持有的资源,而这些线程又反过来在等待第1个线程所持有的资源。

这些条件是死锁产生的必要条件而非充分条件,也就是说只要产生了死锁,那么上面这些条件一定同时成立,但是上述条件即使同时成立也不一定就能产生死锁 。

3.规避死锁的方法

由于锁具有排他性并且锁只能够由其持有线程主动释放,因此由锁导致的死锁只能够从消除“占用并等待资源”和消除“循环等待资源”这两个方向入手 。

  • 粗锁法——使用粗粒度的锁代替多个锁。从消除“占用并等待资源”出发我们不难想到的一种方法就是,采用一个粒度较粗的锁来替代原先的多个粒度较细的锁,这样涉及的线程都只需要申请一个锁从而避免了死锁。 粗锁法的缺点是它明显地降低了并发性并可能导致资源浪费。
  • 锁排序法——相关线程使用全局统一的顺序申请锁。假设有多个线程需要申请资源(锁) {Lock1, Lock2. …, LockN},那么我们只需要让这些线程依照一个全局(相对于使用这种资源的所有线程而言)统一的顺序去申请这些资源,就可以消除“循环等待资源”这个条件,从而规避死锁。
  • 规避死锁的第3种方法是使用 ReentrantLock.tryLock(long,TimeUnit) 申请锁 。ReentrantLock.tryLock(long,TimeUnit)允许我们为锁申请这个操作指定一个超时时间。在超时时间内,如果相应的锁申请成功,那么该方法返回 true; 如果在tryLock(long,TimeUnit)执行的那一刻相应的锁正被其他线程持有,那么该方法会使当前线程暂停,直到这个锁被申请成功(此时该方法返回 true) 或者等待时间超过指定的超时时间(此时该方法返回false)。因此,使用tryLock(long,TimeUnit)来申请锁可以避免一个线程无限制地等待另外一个线程持有的资源,从而最终能够消除死锁产生的必要条件中的“占用并等待资源” 。
  • 一般地,一个方法在持有一个锁的情况下调用一个外部方法,而外部方法往往不在我们(开发人员)的控制范闱之内,其自身可能不会申请另外一个锁,也可能会申请另外一个锁。因此,在持有一个锁的情况下调用一个外部方法的代码很可能会间接导致死锁 。这种情况可以使用开放调用来规避。所谓开放调用 (Open Call) 就是一个方法在调用外部方法的时候不持有任何锁。显然,开放调用能够消除死锁产生的必要条件中的“持有并等待资源”。
  • 使用锁的替代品

4.死锁的恢复

死锁自动恢复的实际意义并不大。原因:

  • 死锁的自动恢复有赖于死锁的线程能够响应中断。
  • 自动恢复尝试可能导致新的问题。

这篇关于20.线程的活性故障:死锁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

JAVA线程的周期及调度机制详解

《JAVA线程的周期及调度机制详解》Java线程的生命周期包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,线程调度依赖操作系统,采用抢占... 目录Java线程的生命周期线程状态转换示例代码JAVA线程调度机制优先级设置示例注意事项JAVA线程

故障定位快人一步! 华为交换机排障命令汇总

《故障定位快人一步!华为交换机排障命令汇总》在使用华为交换机进行故障排查时,首先需要了解交换机的当前状态,通过执行基础命令,可以迅速获取到交换机的系统信息、接口状态以及配置情况等关键数据,为后续的故... 目录基础系统诊断接口与链路诊断L2切换排障L3路由与转发高级调试与日志性能、安全与扩展IT人无数次实战

深入理解Redis线程模型的原理及使用

《深入理解Redis线程模型的原理及使用》Redis的线程模型整体还是多线程的,只是后台执行指令的核心线程是单线程的,整个线程模型可以理解为还是以单线程为主,基于这种单线程为主的线程模型,不同客户端的... 目录1 Redis是单线程www.chinasem.cn还是多线程2 Redis如何保证指令原子性2.

C++实现一个简易线程池的使用小结

《C++实现一个简易线程池的使用小结》在现代软件开发中,多线程编程已经成为提升程序性能的常见手段,本文主要介绍了C++实现一个简易线程池的使用小结,感兴趣的可以了解一下... 在现代软件开发中,多线程编程已经成为提升程序性能的常见手段。无论是处理大量 I/O 请求的服务器,还是进行 CPU 密集型计算的应用

JDK21对虚拟线程的几种用法实践指南

《JDK21对虚拟线程的几种用法实践指南》虚拟线程是Java中的一种轻量级线程,由JVM管理,特别适合于I/O密集型任务,:本文主要介绍JDK21对虚拟线程的几种用法,文中通过代码介绍的非常详细,... 目录一、参考官方文档二、什么是虚拟线程三、几种用法1、Thread.ofVirtual().start(

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

Java JUC并发集合详解之线程安全容器完全攻略

《JavaJUC并发集合详解之线程安全容器完全攻略》Java通过java.util.concurrent(JUC)包提供了一整套线程安全的并发容器,它们不仅是简单的同步包装,更是基于精妙并发算法构建... 目录一、为什么需要JUC并发集合?二、核心并发集合分类与详解三、选型指南:如何选择合适的并发容器?在多

Java中如何正确的停掉线程

《Java中如何正确的停掉线程》Java通过interrupt()通知线程停止而非强制,确保线程自主处理中断,避免数据损坏,线程池的shutdown()等待任务完成,shutdownNow()强制中断... 目录为什么不强制停止为什么 Java 不提供强制停止线程的能力呢?如何用interrupt停止线程s

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消