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

微信网站怎么做的好名字吗/百度热搜榜单

微信网站怎么做的好名字吗,百度热搜榜单,深圳坪山很偏僻吗,南宁网站建设网站目录 死锁 1.构成死锁的场景 (1) 一个线程一把锁 问题描述 解决方案(可重入锁) (2) 两个线程两把锁 问题描述 (3)N个线程 M把锁 哲学家就餐问题 2.死锁的四个必要条件 3.如何解决死锁问题 (1)避免出现请求和保持 (2)打破多个线程的循环等待关系 死锁…

 c96f743646e841f8bb30b2d242197f2f.gif

ddb5ae16fc92401ea95b48766cb03d96.jpeg692a78aa0ec843629a817408c97a8b84.gif


目录

  死锁  

  1.构成死锁的场景  

  (1) 一个线程一把锁   

  问题描述  

  解决方案(可重入锁)  

  (2) 两个线程两把锁  

  问题描述   

  (3)N个线程 M把锁   

  哲学家就餐问题  

  2.死锁的四个必要条件 

  3.如何解决死锁问题  

  (1)避免出现请求和保持  

  (2)打破多个线程的循环等待关系 


  死锁  


  1.构成死锁的场景  


  (1) 一个线程一把锁   


  问题描述  


 我们先来看下面的代码: 

c18ffdbb5cc04c9f8a06d4d2200e2a06.png看起来是两次对同一个引用的加锁,是没有必要的,但是在我们日常学习和工作中,很容易就会写出上述的对一个锁对象进行两次或者多次加锁的操作,此时会出现如下情况:

8a91473519cc4d308594382f01cac541.png

  • 如果第一次加锁要解锁,就必须得先执行完{}中的代码块,就必须进行第二次加锁;
  • 但是第二次加锁时,发现锁对象locker还未被解锁,第二次加锁因此进入阻塞等待的状态,所以第一次加锁的操作无法执行到解锁的位置;
  • 上面的这种情况,就被称为“死锁”(dead lock);死锁是一个非常严重的 bug ,一旦出现,整个线程都会被卡住。

上面的代码虽然会造成死锁,但是我们不太容易写出上面的代码;但是一旦方法调用的层次比较深,就容易出现对同一对象进行多次加锁的情况。 我们再来分析下面的代码:

bdacc8d6936c476bbd6522be3c0685b0.png

  1. 第一次进行加锁操作,能够成功的(锁对象还没有被获取);
  2. 第二次进行加锁,此时意味着,锁对象是已经被占用的状态;第二次加锁,就会触发阻塞等待。

26fb071c000849ac95f85d33308b7eeb.png


  解决方案(可重入锁)  


为了解决上述代码出现的死锁问题, Java 的 synchronized 就引入了可重入的概念;

当 t线程 对 locker对象 加锁成功之后,后续 t 再次针对 locker 进行加锁,不会触发阻塞,而是直接往下走,因为当前 locker 就是被 t 持有~~

ebea33130b7c4b4cb874e110c8e73e04.png


但是,如果是其他线程尝试加锁,就会正常进入阻塞等待的状态;


805cc82e2ba54726a92301bee54b74b4.png


  • 如果发现是同一个锁持有者的线程,则跳过加锁环节;
  • 如果是不同的锁持有者,才会进入阻塞等待。

我们运行刚刚所写的代码,发现程序是可以正常执行的:

118d085356bd478bb7344f8a8f6c9974.png

  • 理论上,程序会被上死锁,但是当我们正在运行程序时,会发现程序依旧可以正常执行,输出结果也正确;
  • 这样的原因是因为 synchronized 的可重入性,解决了当前情况(一个线程针对同一个锁对象进行多次加锁)造成的死锁的问题,哪怕我们再锁三四层,synchronized 的可重入性都会解决该问题。

可重入锁只能针对 一个线程多次对锁对象进行加锁 的情况,如果是其他情况造成的死锁,则无法通过可重入锁解决。

面试官的问题:
如何自己实现一个可重入锁?

  1. 在锁内部记录当前是哪个线程持有的锁,后续每次加锁,都进行判定
  2. 通过计数器,记录当前加锁的次数,从而确定何时真正进行解锁.

  (2) 两个线程两把锁  


  问题描述   


  • 现在有 t1,t2 两个线程,以及 locker1,locker2 两把锁;
  • t1 获取 locker1,t2 获取 locker2 后,t1,t2再分别尝试获取 locker2,locker1,两个线程互不相让,因此进入阻塞等待,最终造成死锁的情况;(家钥匙放车里,车钥匙放家里);

因为上述这种情况,构成的死锁问题的原因,不但因为锁互斥与不可抢占的性质,也因为两个线程在加锁的过程中,造成了请求保持和循环等待;

而造成死锁的原因,是因为两个线程对两个锁对象的加锁,是嵌套的写法。


我们来看下面这段代码:

package Thread;public class Demo22 {public static void main(String[] args) throws InterruptedException {Object locker1 = new Object();Object locker2 = new Object();Thread t1 = new Thread(() -> {System.out.println("t1 获取到 locker1");synchronized (locker1){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (locker2){System.out.println("t1 获取到 locker2");}}});Thread t2 = new Thread(() ->{synchronized (locker2){System.out.println("t2 获取到 locker2");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (locker1){System.out.println("t2 获取到 locker1");}}});t1.start();t2.start();t1.join();t2.join();}
}

代码逻辑:

  1. t1 线程 和 t2 线程 在分别获取到 locker1,locker2 之后,打印日志;
  2. 打印日志后,两个线程分别休眠 1s ,休眠的目的是为了防止系统随机调度线程(抢占式执行),使得其中一个线程一口气获取到 locker1,locker2两把锁;
  3. 在休眠结束后,两个线程分别尝试获取对方已经获取过且没有释放的锁。

143ba47421a64d73a905c8d91f04ad2e.png

我们运行程序,并提供 jconsole 查看 t1,t2 的状态:

5de9724c94e7441c94b52079acd9671c.png

造成死锁之后,t1,t2 都进入阻塞等待的状态,从执行结果的打印日志来看,整个进程被死锁卡在,两个线程各自加第二把锁的时候,jconsolo 的堆栈跟踪也一目了然地表明情况。


  (3)N个线程 M把锁   


  哲学家就餐问题  


0c09f8dc5464488889bb015a40bc037a.png

大部分情况下,上述模型可以很好的运作,但是在一些极端的情况下会造成死锁:
12ed9bc11aeb49babfeff9f3a713658a.png上面的五个线程,都在获取一把锁后,尝试对另一把已经被别的线程获取过的锁,进行加锁,因此所有线程都陷入了阻塞等待的状态,并且五个线程,五把锁之间的等待过程,构成了循环。 

这也使得线程与线程之间,出现了请求保持的情况; 

多个线程,多把锁,出现死锁的情况,如上面吃面造成死锁的这种情况,是比较典型极端的,当然还有更多种出现死锁的情况;

我们先要处理典型的情况,如刚刚吃面的问题,虽然这种情况可能性很小,但是也不能忽略这种情况。


  2.死锁的四个必要条件  


658141553e2e4ff88a945a6982cff111.png

对于我们在上面描述的,构成死锁的三个场景中,只要涉及 N 个线程,M把锁(N>1 && M>1),并且产生了死锁,原因都是满足了上述的四个必要条件。


  3.如何解决死锁问题  


  • 刚刚构成死锁四个必要条件,锁的互斥与不可抢占,是因为锁的基本特性;
  • 要通过解决锁的互斥和不可抢占,来解决死锁问题的做法非常难;
  • 要想打破死锁,避免死锁,我们应该从请求与保持,或者循环等待这两个构成死锁的原因,来寻找突破点。
  • 只要能够解决请求与保持,或者循环等待两个原因中的任意一个,就能够打破死锁~

  (1)避免出现请求和保持  


我们再来分析一下,产生死锁问题的原因,是因为请求保持的代码: 

b7da42e2695346c9b655224fa30e1aaf.png

我们可以发现 ,上述代码中的两个线程,无论是 t1 还是 t2,在进行加锁的代码块中,加锁的方式都是嵌套加锁,这就使得两个线程无法获取对方的锁,又无法解锁,从而双双进入阻塞等待;

换句话说,这种构成死锁情况的原因,就叫做请求保持;


   解决方法:  


对于上图的代码,我们要对其进行修改:

  1. 对于t1线程,把synchronized(locker2) 从 synchronized(locker1)的大括号代码块中取出 
  2. synchronized(locker2) 和 synchronized(locker1) 在 t1 线程中,从嵌套关系变成并列关系;
  3. 对于 t2 线程,也作出同样的修改,使得加锁方式从嵌套加锁,修改为并列加锁:

6444a3f4b9884a9eacf3527791b8df32.png

 执行结果:

96dc79c9832d40ff84775fcf87af6d1a.png

所以,要想解决请求保持,就不要写出嵌套加锁的代码;但是,在日常开发中,确实会出现代码逻辑,必须要通过嵌套加锁,来完成一些操作;所以嵌套加锁很难避免;

因此,我们更通用的打破死锁的做法,就是打破多个线程之间的循环等待关系。


  (2)打破多个线程的循环等待关系  


我们把刚刚的并列加锁代码,还原成嵌套加锁:

3a14ee82ceaf497d980d298c073b88a8.png


只要涉及 N 个线程,M把锁(N>1 && M>1),都可以用“哲学家就餐”模型来进行描述:

ad1cff50084f4e4d87041b7d57cf52d1.png

只要我们对线程的加锁的顺序做出约定;所有的线程,都按照一定顺序进行加锁,就可以破除循环等待条件,进而打破死锁:

(1)

4202253d7678464fad6eef1164bb2af3.png

(2)

9f9d34c664464b839369a6ddd0fb659f.png

(3)

00e76b618f39440ea61fe92860ae8389.png

(4)

b124ca2ecabf4c51900ca4522facb7c1.png

(5)

cbde44c408c44291901cee12e8b7e25a.png

(6)

11420fe10bec453983db912434556664.png

(7)

此时,看着桌子上所剩不多的 CPU 资源,t1瞬间黑化成邪恶栀子花

86d8c595927f43489cd22ecf27ab89ae.png


通过上述“哲学家就餐”模型,我们能直观的发现,只要规定好加锁顺序,就可以打破多个线程循环等待的关系,进而解决死锁问题。


我们回归代码,来感受一下约定加锁顺序(规定每个线程先获取编号小的锁,再去获取编号大的锁)后,带来的效果;

因为五个线程五把锁的情况,并不容易产生死锁,所以我们就用场景二来演示:

d0185cadf99641788399f15753795b2d.png

  • 对于上述代码,我们约定每个线程都先获取编号小的锁对象;
  • t1 先获取 lcoker1,再获取 locker2,满足约定的规则;
  • t2 先获取 locker2,再获取 locker1,不满足约定的规则,所以需要对 t2 进行修改。

d8837ef2b44244db9a56b72f4c4995bc.png执行结果:

192e1da1b13b4928bea2c4c722518617.png约定加锁顺序后,通过修改后代码的执行结果,我们可以看到, 死锁的问题就被完美的解决了~

 c96f743646e841f8bb30b2d242197f2f.gif

692a78aa0ec843629a817408c97a8b84.gif

 

 

相关文章:

【JavaEE初阶 — 多线程】死锁的产生原因和解决方法

目录 死锁 1.构成死锁的场景 (1) 一个线程一把锁 问题描述 解决方案(可重入锁) (2) 两个线程两把锁 问题描述 (3)N个线程 M把锁 哲学家就餐问题 2.死锁的四个必要条件 3.如何解决死锁问题 (1)避免出现请求和保持 (2)打破多个线程的循环等待关系 死锁…...

mapper.xml 使用大于号、小于号示例

<mapper namespace"com.example.EmployeeMapper"><!-- 更新employee_absent_resign_statistics表中的pre_work_date --><update id"updatePreWorkDate"><![CDATA[UPDATE employee e1JOIN employee e2ON e2.statistics_date < e1.s…...

深入了解决策树:机器学习中的经典算法

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

Flutter鸿蒙next 的 Sliver 实现自定义滚动效果

Flutter 提供了一些非常强大的滚动组件&#xff0c;如 ListView、GridView 等&#xff0c;它们可以在滑动时自动处理内容的显示和滚动。但当我们需要更复杂的滚动效果时&#xff0c;Sliver 组件便是一个强大的工具。通过自定义 Sliver&#xff0c;我们可以实现高度定制化的滚动…...

杨中科 .Net Core 笔记 DI 依赖注入

提到依赖不得不提到&#xff0c;控制反转&#xff08;Inversion of Control,IOC&#xff09;这个概念&#xff0c;简单的来讲就是将控制对象的权限交给框架&#xff0c;不再手动完成。IOC实现方式有2种&#xff1a; 1、服务定位器&#xff08;ServiceLocator&#xff09;,主动…...

【RocketMQ】无法访问此网站 http://XXX:10080/ ERR_UNSAFE_PORT

安装完rocketmq-dashboard。打开浏览器访问地址。 问题提示&#xff1a; 无法访问此网站 网址为 http://192.168.22.197:10080/ 的网页可能暂时无法连接&#xff0c;或者它已永久性地移动到了新网址。 ERR_UNSAFE_PORT ‌无法访问10080端口的网站通常是由于Chrome浏览器的安…...

pipreqs:快速准确生成当前项目的requirements.txt,还有和freeze的对比

大家好&#xff0c;这里是程序员晚枫。 今天给大家推荐一个快速生成requirements.txt的小工具&#xff1a;pipreqs。 什么是requirements.txt&#xff1f; 我们在开发Python项目的时候&#xff0c;需要用到requirements.txt来管理项目中使用的第三方库。 当我们把项目部署到…...

Spark 中的 RDD 分区的设定规则与高阶函数、Lambda 表达式详解

Spark 的介绍与搭建&#xff1a;从理论到实践_spark环境搭建-CSDN博客 Spark 的Standalone集群环境安装与测试-CSDN博客 PySpark 本地开发环境搭建与实践-CSDN博客 Spark 程序开发与提交&#xff1a;本地与集群模式全解析-CSDN博客 Spark on YARN&#xff1a;Spark集群模式…...

redis十大数据类型

文章目录 一、redis字符串&#xff08;String&#xff09;set key value同时获取或设置多个键值获取指定区间范围内的值数字增减获取字符串长度和内容追加分布式锁getset&#xff08;先get再set&#xff09; 二、redis列表&#xff08;List&#xff09;通过索引获取列表中的元素…...

国内AI工具复现GPTs效果详解

国内AI工具复现GPTs效果详解 引言 近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;大型语言模型&#xff08;LLM&#xff09;逐渐成为研究和应用的热点。GPTs&#xff08;Generative Pre-trained Transformer&#xff09;系列模型&#xff0c;特别是GPT-4的推出&a…...

【学习笔记】SAP ABAP——OPEN SQL(一)【INTO语句】

【INTO语句】 结构体插入(插入一条语句时) SELECT...INTO [CORRESPONDING FIELDS OF] <wa> FROM <db> WHERE <condition>.内表插入(插入多条语句时) SELECT...INTO|APPENDING [CORRESPONDING FIELDS OF] TABLE <itab>FROM <db> WHERE <con…...

vscode使用之vscode-server离线安装

最近因为想要使用AI工具开始使用vscode&#xff0c;但是在内网使用vscode通过SSH连接虚拟机的centos远程目录却出现了问题&#xff0c;始终连不上&#xff0c;查看原因是centos没有安装vscode-server&#xff0c;网上找各个教程离线安装vscode-code除了浪费时间没有任何收获&am…...

字符编码和字符集

1. 字符编码和字符集 1.1. 字符编码 编码&#xff1a;字符 –>字节解码&#xff1a;字节 –>字符字符编码Character Encoding : 就是一套自然语言的字符与二进制数之间的对应规则。 1.2. 字符集 字符集 Charset&#xff1a;是一个系统支持的所有字符的集合&#xff0…...

【WRF理论第七期】WPS预处理

【WRF理论第七期】WPS预处理 运行WPS&#xff08;Running the WPS&#xff09;步骤1&#xff1a;Define model domains with geogrid步骤2&#xff1a;Extracting meteorological fields from GRIB files with ungrib步骤3&#xff1a;Horizontally interpolating meteorologic…...

Flutter鸿蒙next中的按钮封装:自定义样式与交互

在Flutter应用开发中&#xff0c;按钮是用户界面中不可或缺的组件之一。它不仅用于触发事件&#xff0c;还可以作为视觉元素增强用户体验。Flutter提供了多种按钮组件&#xff0c;如ElevatedButton、TextButton、OutlinedButton等&#xff0c;但有时这些预制的按钮样式无法满足…...

代码随想录算法训练营Day57 | 卡玛网 101.孤岛的总面积、卡玛网 102.沉没孤岛、卡玛网 103. 水流问题、卡玛网 104.建造最大岛屿

目录 卡玛网 101.孤岛的总面积 卡玛网 102.沉没孤岛 卡玛网 103. 水流问题 卡玛网 104.建造最大岛屿 卡玛网 101.孤岛的总面积 题目 101. 孤岛的总面积 思路 代码随想录&#xff1a;101.孤岛的总面积 重点&#xff1a; 首先遍历图的四条边&#xff0c;把其中的陆地及…...

美团代付微信小程序系统 read.php 任意文件读取漏洞复现

0x01 产品简介 美团代付微信小程序系统是美团点评旗下的一款基于微信小程序技术开发的应用程序功能之一,它允许用户方便快捷地请求他人为自己支付订单费用。随着移动支付的普及和微信小程序的广泛应用,美团作为中国领先的本地生活服务平台,推出了代付功能,以满足用户多样化…...

Windows安装tensorflow的GPU版本

前言 首先本文讨论的是windows系统&#xff0c;显卡是英伟达&#xff08;invida&#xff09;如何安装tensorflow-gpu。一共需要安装tensorflow-gpu、cuDNN、CUDA三个东西。其中CUDA是显卡的驱动库&#xff0c;cuDNN是深度学习加速库。 安装开始前&#xff0c;首先需要安装好c…...

2021-04-22 51单片机玩转点阵

理论就不赘述了,网络上多得很,直接从仿真软件感性上操作认识点阵,首先打开ISIS仿真软件,放置一个点阵和电源与地线就可以开始了;由点阵任何一脚连线到地线,另一边对应的引脚就连接到电源,如图:点击运行看是否点亮?看到蓝色与红色的点表示电源正常但是没有任何亮点,这时对调一下…...

lua入门教程:数字

在Lua中&#xff0c;数字&#xff08;number&#xff09;是一种基本数据类型&#xff0c;用于表示数值。以下是对Lua中数字的详细教程&#xff1a; 一、数字类型概述 Lua中的数字遵循IEEE 754双精度浮点标准&#xff0c;可以表示非常大的正数和负数&#xff0c;以及非常小的正…...

[CKS] K8S ServiceAccount Set Up

最近准备花一周的时间准备CKS考试&#xff0c;在准备考试中发现有一个题目关于Rolebinding的题目。 Question 1 The buffy Pod in the sunnydale namespace has a buffy-sa ServiceAccount with permissions the Pod doesn’t need. Modify the attached Role so that it onl…...

QML:Menu详细使用方法

目录 一.性质 二.作用 三.方法 四.使用 1.改变标签 2.打开本地文件 3.退出程序 4.打开Dialog 五.效果 六.代码 在 QML 中&#xff0c;Menu 是一个用于创建下拉菜单或上下文菜单的控件。它通常由多个 MenuItem 组成&#xff0c;每个 MenuItem 可以包含文本、图标和快捷…...

时间复杂度和空间复杂度 part2

一&#xff0c;空间复杂度 空间复杂度是衡量一个算法在执行过程中所需内存空间的量度。它反映了算法随着输入数据规模&#xff08;通常是 nn&#xff09;的增加&#xff0c;所消耗的内存量如何变化。空间复杂度是分析算法效率的一个重要方面&#xff0c;尤其是在内存资源有限的…...

【电机控制器】STC8H1K芯片——UART串口通信

【电机控制器】STC8H1K芯片——UART串口通信 文章目录 [TOC](文章目录) 前言一、UART1.串口初始化2.串口中断3.发送一个字节 二、实验1.原理图2.实验现象 三、参考资料总结 前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、UART 1.串口初始化 …...

STM32移植RT-Thread---时钟管理

一RTT时钟节拍概念 RT-Thread的时钟节拍&#xff08;Tick&#xff09;是操作系统用于管理时间和任务调度的一个基本单位。它在实时操作系统中尤为关键&#xff0c;用于实现任务的延时、超时管理等功能。以下是关于RT-Thread时钟节拍的简单说明&#xff1a; 1.Tick定义&#x…...

Jasypt 实现 yml 配置加密

文章目录 前言一、集成 Jasypt1. pom 依赖2. yml 依赖 3. 加密工具类3. 使用二、常见问题1. application.yml 失效问题2. 配置热更新失败问题 前言 jasypt 官方地址&#xff1a;https://github.com/ulisesbocchio/jasypt-spring-boot Jasypt可以为Springboot加密的信息很多&a…...

uniapp—android原生插件开发(2原生插件开发)

本篇文章从实战角度出发&#xff0c;将UniApp集成新大陆PDA设备RFID的全过程分为四部曲&#xff0c;涵盖环境搭建、插件开发、AAR打包、项目引入和功能调试。通过这份教程&#xff0c;轻松应对安卓原生插件开发与打包需求&#xff01; ***环境问题移步至&#xff1a;uniapp—an…...

NLP之ASR之moonshine:moonshine的简介、安装和使用方法、案例应用之详细攻略

NLP之ASR之moonshine&#xff1a;moonshine的简介、安装和使用方法、案例应用之详细攻略 目录 moonshine的简介 moonshine的安装和使用方法 1、安装 推荐使用uv管理Python环境 安装Moonshine包 Torch后端 TensorFlow后端 JAX后端 ONNX运行时 2、使用方法 0、测试 1…...

albert模型实现微信公众号虚假新闻分类

项目源码获取方式见文章末尾&#xff01; 600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于CNN-RNN的影像报告生成】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实现…...

OceanBase 应用实践:如何处理数据空洞,降低存储空间

问题描述 某保险行业客户的核心系统&#xff0c;从Oracle 迁移到OceanBase之后&#xff0c;发现数据存储空间出现膨胀问题&#xff0c;数据空间 datasize9857715.48M&#xff0c;实际存储占用空间17790702.00M。根据 required_mb - data_mb 值判断&#xff0c;数据空洞较为严重…...