【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.rhkb.cn/news/206509.html

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

相关文章

Ubuntu下载离线安装包

旧版Ubuntu下载地址 https://old-releases.ubuntu.com/releases/ 下载离线包 sudo apt-get --download-only -odir::cache/ncayu install net-tools下载snmp离线安装包 sudo apt-get --download-only -odir::cache/root/snmp install snmp snmpd snmp-mibs-downloadersudo a…

unity Terrain 性能问题

在实践过程中unity发生进入场景GPU爆显存的情况,经过调查发现是使用Terrain造成的问题,这个问题在使用一个Terrain的时候并不会发生,但是在使用多个时会发生。 似乎在使用过程中Terrain会直接把Terrain的整个地图加载,造成移动设…

Ubuntu+Tesla V100环境配置

系统基本信息 nvidia-smi’ nvidia-smi 470.182.03 driver version:470.182.03 cuda version: 11.4 查看系统体系结构 uname -aUTC 2023 x86_64 x86_64 x86_64 GNU/Linux 下载miniconda https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/?CM&OA https://mi…

Dockerfile讲解

Dockerfile 1. 构建过程解析2. Dockerfile常用保留字指令3. 案例3.1. 自定义镜像mycentosjava83.2. 虚悬镜像 4. Docker微服务实战 dockerfile是用来构建docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。 dockerfile定义了进程需要的一切东西&…

[蓝桥杯习题]———位运算、判断二进制1个数

⭐Hello!这里是欧_aita的博客。 ⭐今日语录:行动胜过一切。 ⭐个人主页:欧_aita ψ(._. )>⭐个人专栏: 数据结构与算法(内含蓝桥杯习题) MySQL数据库 位运算 位运算位运算的定义简单运用 实战刷题题目思路代码实现声…

flutter,uni-app开发调试ios

一、申请ios开发者账号 二、ios开发者配置 ios 开发者需要配置的地方 https://developer.apple.com/account/resources/certificates/list Certificates(证书): 作用: 证书用于对应用程序和开发者进行身份验证,确保安全性和可…

mac截图Snagit 中文介绍

1.超越普通的屏幕截图 TechSmith Snagit 是唯一具有内置高级图像编辑和屏幕录制功能的屏幕捕获软件。因此,您可以在一个程序中轻松创建高质量的图像和视频。 2.最后,屏幕捕获软件可以完成您所做的一切 快速解释一个过程如果您正在努力清楚地沟通&…

2023 年 IntelliJ IDEA下载、安装教程,附详细图文

大家好,今天为大家带来的是 2023年 IntelliJ IDEA 下载、安装教程,超详细的图文教程,亲测可用。 文章目录 1 IDEA 下载2 IDEA 安装3 IDEA 使用4 快捷键新手必须掌握:Ctrl:Alt:Shift:Ctrl Alt&a…

STM32CubeIDE(CUBE-MX hal库)----定时器

系列文章目录 STM32CubeIDE(CUBE-MX hal库)----初尝点亮小灯 STM32CubeIDE(CUBE-MX hal库)----按键控制 STM32CubeIDE(CUBE-MX hal库)----串口通信 文章目录 系列文章目录前言一、定时器二、使用步骤三、HAL库实验代码三、标准库代码 前言 STM32定时器是一种多功能外设&#…

【MATLAB】异常数据识别

基于分位数的异常点识别 首先,给定了一个原始数据序列x。然后,计算了序列x的上四分位数和下四分位数,并根据这两个值计算了异常点的阈值。上四分位数减去1.5倍的四分位数范围得到异常值下界,下四分位数加上1.5倍的四分位数范围得…

Selenium介绍及基本使用方法

Selenium是一个开源、免费、简单、灵活,对Web浏览器支持良好的自动化测试工具,在UI自动化、爬虫等场景下是十分实用的,能够熟练掌握并使用Selenium工具可以大大的提高效率。 Selenium简介 Selenium支持多平台、多浏览器、多语言去实现自动化…

【Qt绘图】之绘制坦克

使用绘图事件&#xff0c;绘制坦克。 效果 效果很逼真&#xff0c;想象力&#xff0c;有没有。 示例 代码像诗一样优雅&#xff0c;有没有。 包含头文件 #include <QApplication> #include <QWidget> #include <QPainter>绘制坦克类 class TankWidge…

【docker系列】docker实战之部署SpringBoot项目

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Docker篇之利用docker搭建ftp服务器可实现多用户上传

一、前言 场景&#xff1a;公司需要搭建FTP服务器&#xff0c;供内网之前可以互相传递数据&#xff0c;安全稳定&#xff0c;需要满足开通多个账号&#xff0c;每个用户上传的文件有自己对应的文件目录。 这里建议&#xff1a;用户目录Disk尽量大一点&#xff0c;避免因为空间不…

低代码平台在数字化转型过程中的定位

内容来自演讲&#xff1a;郭昊东 | 上海外服 | 流程分析工程师 摘要 本文介绍了外服集团的 IT 共享中心在低代码平台应用开发方面的实践经验。他们选择低代码平台的原因包括开发成本低、快速看到实际产品以及能够解决数据孤岛和影子 IT 等问题。他们在应用开发中面临的挑战包括…

android shape绘制半圆

<?xml version"1.0" encoding"utf-8"?><shape xmlns:android"http://schemas.android.com/apk/res/android"android:shape"rectangle"><sizeandroid:width"20dp"android:height"10dp" /><…

HBase数据模型杂谈

1.概述 HBase是一个稀疏、多维度、排序的映射表&#xff0c;这张表的索引是行键、列族、列限定符和时间戳。 每个值是一个未经解释的字符串&#xff0c;没有数据类型。用户在表中存储数据&#xff0c;每一行都有一个可排序的行键和任意多的列。表在水平方向由一个或者多个列族…

前端管理制度

数据运营中心的管理形式&#xff1a; 数据运营中心的管理形式 竖向是各小组 横向是项目管理 负责人的定位&#xff1a; 只是工作的内容不同&#xff0c;没有上下级之分 帮助组员找到适合的位置&#xff0c;帮助大家解决问题&#xff0c;给大家提供资源 前端组的工作形式&am…

YOLOV7主干改进,使用fasternet轻量化改进主干(完整教程)

1&#xff0c;Pconv&#xff08;来自Fasternet&#xff09;&#xff08;可作为模型中的基础卷积模块使用&#xff09; 论文链接&#xff1a;https://arxiv.org/abs/2303.03667 2&#xff0c;为了大家方便的使用&#xff0c;这里我对原本的PConv的代码做了部分的改动&#xff0…

系列六、Spring整合单元测试

一、概述 Spring中获取bean最常见的方式是通过ClassPathXmlApplicationContext 或者 AnnotationConfigApplicationContext的getBean()方式获取bean&#xff0c;那么在Spring中如何像在SpringBoot中直接一个类上添加个SpringBootTest注解&#xff0c;即可在类中注入自己想要测试…