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

JavaEE——死锁

前言

死锁是在开发中经常会遇到的一个问题,指的是多个进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象。

1. 死锁的成因

死锁的产生必须要同时满足以下四个条件:

  1. 互斥条件(Mutual Exclusion)
    资源一次只能由一个线程占用,其他线程必须等待该资源释放,不能使用。

  2. 占有并等待(Hold and Wait)
    线程已经持有至少一个资源,并且正在等待获取其他被占用的资源。

  3. 非抢占条件(No Preemption)
    已分配给进程的资源不能被其他线程强行夺取,必须由线程自行释放。

  4. 循环等待(Circular Wait)
    存在一个线程等待的循环链,每个进程都在等待下一个进程所占用的资源。

以下是一个典型的死锁案例:

    public static void main(String[] args) {//死锁案例Object lock1 = new Object();Object lock2 = new Object();Thread t1 = new Thread(() -> {synchronized (lock1) {System.out.println("线程1获取到锁1,等待锁2");try {Thread.sleep(100); // 确保线程2能获取到锁2} catch (InterruptedException e) {e.printStackTrace();}synchronized (lock2) {System.out.println("线程1获取到锁2");}}});Thread t2 = new Thread(() -> {synchronized (lock2) {System.out.println("线程2获取到锁2,等待锁1");try {Thread.sleep(100); // 确保线程1能获取到锁1} catch (InterruptedException e) {e.printStackTrace();}synchronized (lock1) {System.out.println("线程2获取到锁1");}}});}

这四个条件同时成立,就会形成死锁,当我们打破其中任意一个条件,死锁就会消失。

2. 解决死锁问题

上述提到的四个条件,前三个条件都不好打破,第四个是我们最容易破坏的条件,所以为了解决死锁问题,我们最常用的方法就是破坏”循环等待“。

为了破坏这个条件,我们使用锁排序,我们可以把所有的锁进行编号,规定线程按照固定的编号顺序来获取锁,这样就可以避免环路的产生。

就如上面展示的死锁代码,我们把获取锁的顺序进行修改,就可以防止死锁的产生:

        //死锁案例Object lock1 = new Object();Object lock2 = new Object();Thread t1 = new Thread(() -> {synchronized (lock1) {try {Thread.sleep(100); } catch (InterruptedException e) {e.printStackTrace();}synchronized (lock2) {System.out.println("线程1获取到锁2");}}});Thread t2 = new Thread(() -> {synchronized (lock1) {try {Thread.sleep(100); } catch (InterruptedException e) {e.printStackTrace();}synchronized (lock2) {System.out.println("线程2获取到锁1");}}});}

这里统一了线程对锁的获取顺序,组织了等待环路的产生。

总结

本篇文章简单的介绍了我们常常遇到的死锁问题,讲述了死锁的成因及其解决方法,希望通过这篇文章,能够加深你对死锁的理解,能够轻松的发现并应对可能产生的死锁问题。

http://www.dtcms.com/a/283468.html

相关文章:

  • PowerBI实现仅在需要图表时显示图表
  • 傅里叶变换算子性质证明
  • GTSuite许可管理常见问题及解决方案
  • 基于FPGA的IIC控制EEPROM读写(1)
  • Mybatis07-逆向工程
  • 《python语言程序设计》2018版第8章5题编写函数统计特定不重复字符串s2在s1中的出现次数
  • C#获取当前系统账户是否为管理员账户
  • 资源利用率提升50%:Serverless 驱动国诚投顾打造智能投顾新范式
  • 用Amazon Q Developer助力Python快捷软件开发
  • EMS4000/EMS3900/EMS4100/EMS3157/EMS/23157高性能高质量模拟开关芯片
  • Go语言自学笔记(2.3-2.6)
  • C++:vector(2)之vector的模拟实现
  • 使用 SeaTunnel 建立从 MySQL 到 Databend 的数据同步管道
  • [2025CVPR-图象检索方向]CCIN:用于合成图像检索的合成冲突识别和中和模型
  • OWASP Top 10 攻击场景实战
  • 简单易懂,什么是连续分配管理方式
  • Vue3+Ts实现父子组件间传值的两种方式
  • 设计模式之【观察者模式】
  • 多维动态规划题解——不同路径【LeetCode】记忆化搜索
  • ai 编程工具,简单总结
  • 16路串口光纤通信FPGA项目实现指南 - 第二部分(下)
  • Day36 Java方法和流程控制练习 计算器
  • Linux运维新手的修炼手扎之第19天
  • Linux内核设计与实现 第1章:内核简介
  • UDP和TCP的主要区别是什么?
  • --- Bean 的生命周期 ---
  • Redis键过期后会立即删除吗
  • 光环效应(HALO Effect)
  • MySQL高并发高可用架构设计与实现:主从复制与读写分离
  • x86版Ubuntu的容器中运行ARM版Ubuntu