【JavaEE】多线程 -- 死锁问题

目录

1. 问题引入

2.死锁问题的概念和原因

 3. 解决死锁问题


1. 问题引入

在学习死锁之前, 我们先观察下面的代码能否输出正确的结果:

运行程序, 能正常输出结果:

这个代码只管上看起来, 好像是有锁冲突的, 此时的 locker 对象已经是加锁的状态, 在尝试对 locker 加锁, 不应该会出现阻塞问题吗?

其实, 问题的关键是,这两次加锁, 其实是在同一个线程上进行的.  由于是同一个线程, 此时锁对象就知道了第二次加锁的线程,  第二次加锁操作就可以直接放行通过, 不会出现阻塞.  这个特性称为 "可重入". 

使用可重入锁, 可以避免代码出现死锁问题, 如果使用的不是可重入锁, 就会出现死锁问题.

2.死锁问题的概念和原因

Java多线程中的死锁问题是指两个或多个线程互相持有对方所需的资源而无法继续执行的情况。这种情况下,线程无法释放已经占有的资源,也无法获取自己所需的资源,导致程序无法继续执行下去。

通常,发生死锁问题需要满足以下四个条件:

  1. 互斥条件(Mutual exclusion):至少有一个资源同时只能被一个线程占用。
  2. 请求与保持条件(Hold and wait):线程至少已经占有一个资源,并且正在请求另一个被其他线程占用的资源。
  3. 不可剥夺条件(No preemption):已经分配给一个线程的资源不能被强制剥夺。
  4. 循环等待条件(Circular wait):存在一个线程链,每个线程都在等待下一个线程所占有的资源。

死锁的例子:

线程1获取到锁A, 线程2获取到锁B, 接下来, 线程1尝试获取锁 B, 线程2尝试获取锁A, 此时出现了死锁问题:  

package thread;public class ThreadDemo22 {public static void main(String[] args) {Object A = new Object();Object B = new Object();Thread t1 = new Thread(()-> {synchronized (A) {// sleep 是为了t2时间, 让t2也能拿到 Btry {Thread.sleep(1000);}catch (InterruptedException e) {e.printStackTrace();}//尝试获取B, 并没有释放 Asynchronized (B) {System.out.println("t1拿到了两把锁");}}});Thread t2 = new Thread(()->{synchronized (B) {// sleep 是给t1时间, 让t1能拿到 Atry {Thread.sleep(1000);}catch (InterruptedException e) {e.printStackTrace();}//尝试获取A, 并没有释放 Bsynchronized (A) {System.out.println("t2拿到了两把锁");}}});t1.start();t2.start();}
}

 程序没有任何输出结果:

 3. 解决死锁问题

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

  1. 避免使用多个锁:尽量减少使用多个锁,如果必须使用多个锁,确保获取锁的顺序是一致的,以减少死锁的可能性。
  2. 加锁顺序:多个线程获取锁的顺序要保持一致,避免出现循环等待条件。
  3. 加锁时限:在获取锁的时候设置超时时间,如果一段时间内没有获取到锁,就放弃当前的操作,释放已经持有的锁,避免长时间等待导致死锁。
  4. 死锁检测:通过监控线程的状态和资源的使用情况,及时检测并解决潜在的死锁问题。

对于死锁例子, 我们可以使两个线程的取锁顺序保持一致:

package thread;public class ThreadDemo22 {public static void main(String[] args) {Object A = new Object();Object B = new Object();Thread t1 = new Thread(()-> {synchronized (A) {// sleep 是为了t2时间, 让t2也能拿到 Btry {Thread.sleep(1000);}catch (InterruptedException e) {e.printStackTrace();}//尝试获取B, 并没有释放 Asynchronized (B) {System.out.println("t1拿到了两把锁");}}});Thread t2 = new Thread(()->{synchronized (A) {// sleep 是给t1时间, 让t1能拿到 Atry {Thread.sleep(1000);}catch (InterruptedException e) {e.printStackTrace();}//尝试获取A, 并没有释放 Bsynchronized (B) {System.out.println("t2拿到了两把锁");}}});t1.start();t2.start();}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/235587.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是PDN的交流阻抗?

什么是PDN的交流阻抗? 在电力电子领域,PDN(Power Distribution Network)的交流阻抗是一个重要的概念,它反映了PDN在交流电源和负载之间传输电能的能力。了解PDN的交流阻抗对于优化电源设计、提高系统性能和可靠性具有重…

[iOS学习笔记]浅谈RunLoop底层

RunLoop是什么? RunLoop是iOS开发中比较重要的知识点,它贯穿程序运行的整个过程。它是线程基础架构的一部分,是一种保障线程循环处理事件而不会退出的机制。同时也负责管理线程需要处理的事件,让线程有事儿时忙碌,没事…

全网最牛最全面的Jmeter接口测试:jmeter_逻辑控制器_事务控制器

事务: 性能测试中,事务指的是从端到端,一个完整的操作过程,比如一次登录、一次 筛选条件查询,一次支付等;技术上讲:事务就是由1个或多个请求组成的 事务控制器 事务控制器类似简单控制器&…

spring框架的事务传播级别经典篇

一 spring事务传播级别 1.1 总结概述 方法A:外围方法,方法B:内部方法,在A中调用B 1.事务级别PROPAGATION_REQUIRED: 如果A为PROPAGATION_REQUIRED:B 不管有没有设置事务级别,都会加入到A的事务级别中。如…

科学上网也clone不全PX4?

一、问题 已经科学上网,下载PX4固件 git clone https://github.com/PX4/Firmware.git --recursivePX4大框架 clone 下来了,但是内部的子模块很多没有,报了很多 Fatal,例如 fatal: clone of https://github.com/px4/cyclonedds …

【Java线程通信】一窥究竟

今天我们要聊一聊Java线程通信。如果你是一个Java开发者,那么你肯定知道线程是Java中的一个重要概念。线程是程序执行的最小单位,它可以独立运行,也可以与其他线程共享资源。那么,线程之间如何进行通信呢?这就是我们今…

代理模式 1、静态代理 2、动态代理 jdk自带动态代理 3、Cglib代理

文章目录 代理模式1、静态代理2、动态代理jdk自带动态代理 3、Cglib代理 来和大家聊聊代理模式 代理模式 代理模式:即通过代理对象访问目标对象,实现目标对象的方法。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操…

EI级 | Matlab实现TCN-BiLSTM-Multihead-Attention多头注意力机制多变量时间序列预测

EI级 | Matlab实现TCN-BiLSTM-Multihead-Attention多头注意力机制多变量时间序列预测 目录 EI级 | Matlab实现TCN-BiLSTM-Multihead-Attention多头注意力机制多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.【EI级】Matlab实现TCN-BiLSTM-Multihead-…

Containerd Container管理功能解析

Containerd Container管理功能解析 container是containerd的一个核心功能,用于创建和管理容器的基本信息。 本篇containerd版本为v1.7.9。 更多文章访问 https://www.cyisme.top 本文从ctr c create命令出发,分析containerd的容器及镜像管理相关功能。 …

【Vulnhub 靶场】【DriftingBlues: 9 (final)】【简单】【20210509】

1、环境介绍 靶场介绍:https://www.vulnhub.com/entry/driftingblues-9-final,695/ 靶场下载:https://download.vulnhub.com/driftingblues/driftingblues9.ova 靶场难度:简单 发布日期:2021年05月09日 文件大小:738 …

数字图像处理(实践篇)一 将图像中的指定目标用bBox框起来吧!

目录 一 实现方法 二 涉及的OpenCV函数 三 代码 四 效果图 一 实现方法 ①利用OTSU方法将前景与背景分割。 ②使用连通区域分析可以将具有相同像素值且位置相邻的前景像素点组成的图像区域识别。 ③画bbox。 ④显示结果。 二 涉及的OpenCV函数 ① OpenCV提供了cv2.th…