Java中死锁和释放锁的基本介绍和细节讨论

news/2024/6/17 23:01:46 标签: java, jvm, 开发语言

死锁(Deadlock)是多线程编程中的一个经典问题,指的是两个或多个线程互相等待对方释放资源,从而导致程序无法继续执行的状态

死锁产生的条件,通常被称为死锁的“必要条件”,包括:

  1. 互斥条件(Mutual Exclusion): 一个资源同时只能被一个线程占用。

  2. 请求与保持条件(Hold and Wait): 一个线程在持有一个资源的同时,又请求另一个资源。

  3. 不剥夺条件(No Preemption): 资源只能由持有它的线程释放,不能被强制性地剥夺。

  4. 循环等待条件(Circular Wait): 若干线程之间形成一种头尾相接的循环等待资源的关系。

死锁代码:

java">public class DeadLock {
    public static void main(String[] args) {
        //模拟死锁现象
        DeadLockDemo A = new DeadLockDemo(true);
        Thread thread1 = new Thread(A);
        thread1.setName("A 线程");
        DeadLockDemo B = new DeadLockDemo(false);
        Thread thread2 = new Thread(B);
        thread2.setName("B 线程");
        thread1.start();
        thread2.start();
    }
}

class DeadLockDemo implements Runnable{
    static final Object o1 = new Object();// 保证多线程,共享一个对象,这里使用 static
    static final Object o2 = new Object();
    boolean flag;
    public DeadLockDemo(boolean flag) {//构造器
        this.flag = flag;
    }
    @Override
    public void run() {
        //下面业务逻辑的分析
        //1. 如果 flag 为 T, 线程 A 就会先得到/持有 o1 对象锁, 然后尝试去获取 o2 对象锁
        //2. 如果线程 A 得不到 o2 对象锁,就会 Blocked
        //3. 如果 flag 为 F, 线程 B 就会先得到/持有 o2 对象锁, 然后尝试去获取 o1 对象锁
        //4. 如果线程 B 得不到 o1 对象锁,就会 Blocked
        if (flag) {
            synchronized (o1) {//对象互斥锁, 下面就是同步代码
                System.out.println(Thread.currentThread().getName() + " 进入 1");
                synchronized (o2) { // 这里获得 li 对象的监视权
                    System.out.println(Thread.currentThread().getName() + " 进入 2");
                }
            }
        } else {
            synchronized (o2) {
                System.out.println(Thread.currentThread().getName() + " 进入 3");
                synchronized (o1) { // 这里获得 li 对象的监视权
                    System.out.println(Thread.currentThread().getName() + " 进入 4");
                }
            }
        }
    }
}

为了避免死锁,可以采取以下策略:

  1. 破坏互斥条件: 在某些情况下,可以让多个线程共享某些资源,避免互斥。

  2. 破坏请求与保持条件: 要求一个线程在请求资源时,释放已持有的资源。

  3. 破坏不剥夺条件: 允许操作系统剥夺某些线程的资源。

  4. 破坏循环等待条件: 对资源进行排序,按照一定的顺序申请资源,避免形成环状等待。

释放锁的操作一般发生在线程使用完共享资源后,应当确保及时释放资源以允许其他线程使用。Java 中,释放锁通常在以下4种情况下发生

  1. 线程执行完共享资源的操作后,应该显式地调用释放锁的方法,例如使用 synchronized关键字时,在代码块执行完毕后会自动释放锁
  2. 当前线程在同步代码块、同步方法中遇到break或return
  3. 如果在使用共享资源的过程中抛出异常,为了避免资源一直被占用,应当在异常处理代码中释放锁。
  4. 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁

下面的操作不会释放锁

  1. 线程执行同步代码块或同步方法时,程序调用**Thread.sleep()、Thread.yield()**暂停当前线程的执行,不会释放锁
  2. 线程执行同步代码块时,其他线程调用了该线程的**suspend()**将该线程挂起,该线程不会释放锁。suspend()和resume()已经过时,尽量避免使用

确保正确地释放锁对于避免死锁和保证多线程程序的正确性非常重要。

总之,死锁是多线程编程中需要注意的重要问题,应当谨慎设计和管理多线程程序,避免死锁的产生,并在合适的时机释放锁以确保程序的正常运行。


http://www.niftyadmin.cn/n/4981231.html

相关文章

WSL Opencv with_ffmpeg conan1.60.0

我是ubuntu18. self.options[“opencv”].with_ffmpeg True 关键是gcc版本需要conan支持,比如我的是: compilergcc compiler.version7.5 此外还需要安装系统所需库: https://qq742971636.blog.csdn.net/article/details/132559789 甚至来…

Java网络爬虫——jsoup快速上手,爬取京东数据。同时解决‘京东安全’防爬问题

Java网络爬虫——jsoup快速上手,爬取京东数据。同时解决‘京东安全’防爬问题 介绍 网络爬虫,就是在浏览器上,代替人类爬取数据,Java网络爬虫就是通过Java编写爬虫代码,代替人类从网络上爬取信息数据。程序员通过设定…

Linux系列讲解 —— 【systemd】下载及编译记录

Ubuntu18.04的init程序合并到了systemd中,本篇文章记录一下systemd的下载和编译。 1. 下载systemd源码 (1) 查看systemd版本号,用来确定需要下载的分支 sunsun-pc:~$ systemd --version systemd 237 PAM AUDIT SELINUX IMA APPARMOR SMACK SYSVINIT UT…

深入详解ThreadLocal

本文已收录至GitHub,推荐阅读 👉 Java随想录 微信公众号:Java随想录 原创不易,注重版权。转载请注明原作者和原文链接 文章目录 什么是ThreadLocalThreadLocal 原理set方法get方法remove方法 ThreadLocal 的Hash算法ThreadLocal …

学习JAVA打卡第四十五天

StringBuffer类 StringBuffer对象 String对象的字符序列是不可修改的,也就是说,String对象的字符序列的字符不能被修改、删除,即String对象的实体是不可以再发生变化,例如:对于 StringBuffer有三个构造方法&#xff…

Matlab图像处理-平移运算

几何运算 几何运算又称为几何变换,是将一幅图像中的坐标映射到另外一幅图像中的新坐标位置,它不改变图像的像素值,只是改变像素所在的几何位置,使原始图像按照需要产生位置、形状和大小的变化。 图像几何运算的一般定义为&#…

RT_Thread内核机制学习(一)

ARM架构及汇编 ARM芯片属于精简指令集计算机(RISC:Reduced Instruction Set Computer),它所使用的指令比较简单,有如下特点: 对内存只有读、写指令。对于数据的运算实在CPU内部实现。使用RISC指令的CPU复杂…

mac 安装Metasploit

官网安装:https://docs.metasploit.com/docs/using-metasploit/getting-started/nightly-installers.html 直接下载:https://osx.metasploit.com/metasploitframework-latest.pkg