当前位置: 首页 > news >正文

Java高频面试之并发编程-28

hello啊,各位观众姥爷们!!!本baby今天又来报道了!哈哈哈哈哈嗝🐶

面试官:线程死锁了解吗?该如何避免?


线程死锁的原理及避免方法
线程死锁是多线程编程中因资源竞争导致的僵局,多个线程互相持有对方所需资源且不释放,导致所有线程永久阻塞。理解其原理并采取预防措施是避免死锁的关键。


一、死锁产生的四个必要条件

  1. 互斥条件(Mutual Exclusion)
    资源一次只能被一个线程占有(如锁、文件句柄等独占资源)。
  2. 占有且等待(Hold and Wait)
    线程在持有至少一个资源的同时,等待获取其他线程占有的资源。
  3. 不可抢占(No Preemption)
    资源只能由持有线程主动释放,不能被其他线程强行抢占。
  4. 循环等待(Circular Wait)
    存在一个线程等待链,每个线程都在等待下一个线程持有的资源。

二、死锁示例

// 线程 A
synchronized (lock1) {Thread.sleep(100);synchronized (lock2) { ... }
}// 线程 B
synchronized (lock2) {Thread.sleep(100);synchronized (lock1) { ... }
}

两个线程以不同顺序获取 lock1lock2,可能进入死锁状态。


三、避免死锁的常用方法

1. 破坏“占有且等待”条件
  • 一次性申请所有资源:线程在运行前申请所有需要的资源,若无法满足则等待。
    // 通过一个全局锁一次性获取所有资源
    synchronized (globalLock) {synchronized (lock1) {synchronized (lock2) { ... }}
    }
    
  • 适用场景:资源需求明确且数量固定。
2. 破坏“不可抢占”条件
  • 超时释放:尝试获取锁时设置超时,失败后释放已有资源并重试。
    ReentrantLock lock1 = new ReentrantLock();
    ReentrantLock lock2 = new ReentrantLock();// 尝试获取锁,超时后释放
    if (lock1.tryLock(1, TimeUnit.SECONDS)) {try {if (lock2.tryLock(1, TimeUnit.SECONDS)) {try { ... } finally { lock2.unlock(); }}} finally { lock1.unlock(); }
    }
    
  • 工具支持:使用 ReentrantLocktryLock() 方法。
3. 破坏“循环等待”条件
  • 固定资源申请顺序:所有线程按相同顺序获取资源。
    // 统一先获取 lock1,再获取 lock2
    synchronized (lock1) {synchronized (lock2) { ... }
    }
    
  • 哈希排序法:根据资源唯一标识(如哈希值)排序后再申请。
    Object[] locks = { lock1, lock2 };
    Arrays.sort(locks); // 按哈希值排序synchronized (locks[0]) {synchronized (locks[1]) { ... }
    }
    
4. 资源分配算法(预防死锁)
  • 银行家算法
    系统预判资源分配是否会导致死锁,仅在安全状态下分配资源。
    • 实现复杂度高,多用于理论场景,实际开发中较少直接使用。

四、死锁检测与恢复

1. 检测方法
  • 监控工具
    • jstack:生成线程转储,分析线程堆栈中的锁持有和等待关系。
    • VisualVM、JConsole:图形化工具查看线程状态。
  • 日志分析:记录资源申请和释放日志,分析潜在死锁链。
2. 恢复策略
  • 资源抢占:强制释放某线程持有的资源(可能导致数据不一致)。
  • 线程终止:终止部分线程以打破循环等待(需谨慎处理业务状态)。

五、实际开发中的最佳实践

  1. 减少锁粒度:使用细粒度锁(如 ConcurrentHashMap 分段锁)。
  2. 减少锁持有时间:尽快释放锁,避免在锁内执行耗时操作(如 I/O)。
  3. 避免嵌套锁:尽量使用单一锁,或按固定顺序获取多个锁。
  4. 使用高层并发工具
    • Executor 框架管理线程池。
    • CountDownLatchCyclicBarrier 替代显式锁。
    • 使用无锁数据结构(如 AtomicIntegerDisruptor)。

六、总结

避免死锁方法核心思想适用场景
固定资源顺序破坏循环等待条件多锁嵌套场景
超时释放破坏不可抢占条件高竞争、复杂同步逻辑
一次性申请资源破坏占有且等待条件资源需求明确且固定
无锁编程避免互斥条件计数器、状态标志等简单操作

关键原则

  • 早发现:通过代码审查和工具监控预防潜在死锁。
  • 早规避:在设计和编码阶段采用固定顺序、超时等策略。
  • 简化逻辑:减少不必要的同步,优先使用线程安全库。

你想要的技术资料我全都有:https://pan.q删掉汉子uark.cn/s/aa7f2473c65b

在这里插入图片描述


文章转载自:

http://W4tyFUXt.fsjcn.cn
http://yM3bnYiM.fsjcn.cn
http://AyVO9Sw8.fsjcn.cn
http://TasaDn58.fsjcn.cn
http://CmqlVLAg.fsjcn.cn
http://UG6jCXnX.fsjcn.cn
http://IpuHtdYH.fsjcn.cn
http://EzWYMKep.fsjcn.cn
http://abneBVC0.fsjcn.cn
http://jRY1tFt8.fsjcn.cn
http://WotyfSjs.fsjcn.cn
http://M6ZBJ8kU.fsjcn.cn
http://ARdsuSOQ.fsjcn.cn
http://wmNy9wrX.fsjcn.cn
http://aYXtKjv3.fsjcn.cn
http://rwKlYQSN.fsjcn.cn
http://K3yA7NXM.fsjcn.cn
http://csJMb4wJ.fsjcn.cn
http://1MUAi5ad.fsjcn.cn
http://m73fOEoP.fsjcn.cn
http://ow9R3dJg.fsjcn.cn
http://axb7fLGx.fsjcn.cn
http://rRZXcccJ.fsjcn.cn
http://nRXQ1T6c.fsjcn.cn
http://Qrv3SnL7.fsjcn.cn
http://9dPtPJOY.fsjcn.cn
http://1hRiaLHA.fsjcn.cn
http://pYzH9waH.fsjcn.cn
http://umRaR84x.fsjcn.cn
http://cjlTybiF.fsjcn.cn
http://www.dtcms.com/a/247257.html

相关文章:

  • 剑指offer23_树的子结构
  • 深度学习之模型压缩三驾马车:基于ResNet18的模型剪枝实战(3)
  • ubuntu安装libevent
  • 如何连上Nacos
  • 产品成本分析怎么做?从0到1搭建全生命周期分析框架!
  • JDK版本如何丝滑切换
  • BeanUtil.copyProperties()进行属性拷贝时如何忽略NULL值——CopyOptions配置详解
  • CKA考试知识点分享(12)---configmap
  • 005__C++类的基本语法
  • 洛谷P4555 最长双回文串
  • 从监测滞后到全域智控:河湖智慧化管理方案
  • python程序设计(2)
  • LeetCode 72. 编辑距离(Edit Distance)| 动态规划详解
  • 【推荐算法课程二】推荐算法介绍-深度学习算法
  • 日语语法学习
  • 模型合并(model merge)
  • CC工具箱使用指南:【面要素四至】
  • 报表工具顶尖对决系列—关联过滤
  • /proc/<pid>/maps文件格式详解
  • 声学成像仪在电力行业的应用品牌推荐
  • JavaWeb期末速成 Servlet
  • [C++11] : 谈谈包装器和lambda表达式,仿函数,bind的坑
  • Ntfs!NtfsVolumeCheckpointDpc函数分析到调用Ntfs!NtfsCheckpointAllVolumes函数
  • ubuntu 挂载问题
  • 【51单片机】6. 定时器、按键切换流水灯时钟Demo
  • Harbor 2.12.2 and 2.12.3 初始化密码错误
  • 风控系统中,要调用第三方服务获取信息,很慢,如何解决?
  • Pytorch中view函数详解和工程实战示例
  • Vue + element实现电子围栏功能, 根据省市区选择围栏, 自定义围栏 ,手动输入地名围栏, 保存围栏,清除围栏,加载围栏,批量检测标点是否在围栏内。
  • 杭州电商代运营公司排名前十