内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间

你是否因为写出死锁导致半夜加班,扣绩效?你是否为小白程序员,还没有接触过并发编程不知道什么死锁,你是否希望通过并发编程这块突破自己的瓶颈,在新的一年挑战高薪?那么Java并发编程中的死锁是你避不开的。,在通过Redis或者zookeeper实现分布式锁时也可能出现死锁,本篇文章从Java线程入手,解密以下几点:,什么是死锁,死锁如何产生,通过有趣的案例实现死锁,并分析原因,分析死锁产生的四个必要条件,并且解决死锁,通过Java自带工具检测和定位死锁位置,通过银行家算法,规避死锁问题,死锁是进程死锁的简称,是由Dijkstra于1965年研究银行家算法时首先提出来的。它是计算机操作系统乃至并发程序设计中最难处理的问题之一。实际上,死锁问题不仅在计算机系统中存在,在我们日常生活中它也广泛存在。,我们来看一个死锁例子:,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,公司需要有工作经验的员工,而刚毕业的小伙伴需要工作来获得工作经验,这样企业和应届生之间就产生了死锁现象,这样的例子还有很多,比如:两辆车过桥,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,电影中的经典情节:我要的货呢,你带钱没有,最后一手交钱一手交货,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,所谓的死锁其实是一种现象,就是两个或两个以上线程的多线程情况下,多个线程同时被阻塞,它们中的一个或全部都在等待某一锁资源的释放,由于线程被无期限的阻塞,因此程序不会继续执行,表现为卡住不动。,如:线程1和线程2的运行都需要A资源和B资源,此时线程1获取了A资源,线程2获取到了B锁,此时线程1获取不到B锁和线程2获取不到A锁,导致两个线程彼此僵持!,之前文章中的案例都是使用一把锁,死锁是线程需要多把锁才会出现,那么什么场景下需要多把锁呢?,家中住着张三和翠花夫妻二人,家庭条件一般,只有一个厨房,希望实现翠花做饭和张三洗菜互不相干,分析:,厨房类:,运行结果:,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,使用一把锁的时候性能较低,因为锁的范围太大了,直接将厨房锁住,只需将房间内的每一个功能单独锁起来即可,比如:单独将洗菜,做饭,使用冰箱锁住,不能多人同时使用,应该将锁细化,这样同一个房间就可以同时做很多工作,厨房的利用率就会上来,洗菜和做饭可以同步进行,这样是不就可以早点吃上美味了呢!,厨房改造:,运行结果:,发现做饭【煮粥】和洗菜是同时开始的,通过细化锁,可以提升程序性能,必须要保障两个操作没有关联性,比如煮粥不需要等菜洗好,如果是炒菜,就需要等待菜洗好才可以进行。,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,锁细粒度化的好处是:提高程序等性能,弊端在于:如果一个线程同时需要多把锁,就可能产生死锁,以上边的企业和面试者为例演示死锁,企业招工需要有工作经验的程序员,但是添甄刚毕业,没有工作经验,需要有工作才能获取工作经验,这样就导致企业招不到人,面试者找不到工作的尴尬境地!,运行结果:发现程序再企业和面试者各输出一句之后卡死不动,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,简单的说就是:我需要的东西你占着,你需要的东西我占着,而且我们都不会脑筋急转弯,就傻傻的等着对方让步,拿到自己需要的东西之后继续玩,但是大家都这么想那就谁也别玩了。,当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。,死锁检测其实非常简单,这里介绍两种方式监测死锁,如果你有更好的办法或工具记得在评论区分享哦!,1、window下通过任务管理器查看进程内存占用情况,Linux下通过 top 命令查看,这里以window为例,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,2、通过jps命令获取该进程的进程号也就是PID,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,3、通过 jstack PID 查看进程信息,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,接下来的信息:在jstack输出的信息中最后出现了死锁提示,提示显示在DeadThread.java文件的第39行和23行,那你去排查代码就可以啦,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,这个工具在查看JVM内存时也是可以使用的,它是JDK中携带官方提供的工具,无需下载第三方插件即可使用,1、打开 jconsole 工具,在命令行输入jconsole即可开启,箭头右侧就是该工具启动页,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,2、选择对应的Java进程查看信息,双击选中PID为128的Java进程,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,3、选中线程,点击下方检查死锁按钮,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,4、死锁检测结果,也会将死锁的信息展示出开【右侧信息需要双击左侧线程名才会展示出来】,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,这里说的避免死锁,其实是在生产环境中也就是项目上线运行不要出现死锁,不然又要被喊过去加班了,上边说了死锁产生的四个条件,只要我们将这四个条件中的任意一个破坏就不会产生死锁。,比如,企业和面试者的案例,调换两者加锁顺序一致即可解决死锁问题,运行结果:,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,此时就不会出现死锁,当企业线程运行占用work锁,这是如果发生线程切换,面试者也是要获取work锁,此时发现获取不到,就会进入阻塞,CPU放弃执行转而执行企业线程,此时企业线程获取workExperience锁,因为加锁顺序相同,此锁必然没有被比别的线程占用可以获得,继续执行,但是此时就无法实现交替执行,如果需要交替执行则需要使用线程通信实现,后边会安排此部分内容,因为 synchronized 不会自动释放,无法设置超时时间,此方案需要通过Lock接口实现,改接口在Java并发编程合集的《Java线程安全问题和解决方案》一文中有详细介绍,此方法一定要记得调用unlock释放锁,同样可以解决死锁问题,因为不会像 synchronized 一样无脑等待,而是非常机智,如果拿不到就不要了,就好比追一个女孩子,追了三年还不行就放弃吧,而synchronized就是永不言弃,等到天荒地老,非常痴情。倾我半世阳光,许你天荒地老,银行家算法是一种最有代表性的避免死锁的算法。又被称为资源分配拒绝法。 在避免死锁方法中允许进程动态地申请资源,但系统在进行资源分配之前,应先计算此次分配资源的安全性,若此次分配不会导致系统进入不安全状态,则将资源分配给线程,否则进程等待,银行家算法中的数据结构,1、可利用资源向量Available 是个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目。如果Available[j]=K,则表示系统中现有Rj类资源K个。,2、最大需求矩阵Max 这是一个n×m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max[i,j]=K,则表示进程i需要Rj类资源的最大数目为K。,3、分配矩阵Allocation 这也是一个n×m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果Allocation[i,j]=K,则表示进程i当前已分得Rj类资源的数目为K。,4、需求矩阵Need 这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要Rj类资源K个,方能完成其任务。 Need[i,j]=Max[i,j]-Allocation[i,j],操作系统的两种状态,安全序列:是指一个进程序列{P1,…,Pn}是安全的,即对于每一个进程Pi(1≤i≤n),它以后尚需要的资源量不超过系统当前剩余资源量与所有进程Pj (j < i )当前占有资源量之和。,1、安全状态:如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态。安全状态一定是没有死锁发生。,2、不安全状态:不存在一个安全序列。不安全状态不一定导致死锁。,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,首先判断一下当前的安全序列: 当前状态,可利用资源向量有 1 6 2 2,1、P0: 已分配 0 0 3 2, 还需要 0 0 1 2,当前可利用资源 1 6 2 2足够分配给P0; Process Allocation Need Available(Available-Need) Available+Allocation P0 0 0 4 4 0 0 0 0 1 6 1 0 1 6 5 4 P0分配成功:进入安全序列,分配完成后,将资源还给可利用资源,2、P1:已分配1 0 0 0, 还需要 1 7 5 0,当前可利用资源 1 6 5 4不够分配给P1; P1分配失败,3、P2: 已分配1 3 5 4, 还需要 2 3 5 6,当前可利用资源 1 6 5 4不够分配给P2; P2分配失败,4、P3: 已分配 0 3 3 2, 还需要 0 6 5 2,当前可利用资源 1 6 5 4足够分配给P3; Process Allocation Need Available(Available-Need) Available+Allocation P3 0 9 8 4 0 0 0 0 1 0 0 2 1 9 8 6 P3分配成功,进入安全序列,分配完成后,将资源还给可利用资源,5、P4: 已分配 0 0 1 4, 还需要 0 6 5 6,当前可利用资源 1 9 8 6足够分配给P4; Process Allocation Need Available(Available-Need) Available+Allocation P4 0 6 6 10 0 0 0 0 1 3 3 0 1 9 9 10 P4分配成功,进入安全序列,分配完成后,将资源还给可利用资源,6、P1: 已分配 1 0 0 0, 还需要 1 7 5 0,当前可利用资源 1 9 9 10足够分配给P1; Process Allocation Need Available(Available-Need) Available+Allocation P1 2 7 5 0 0 0 0 0 0 2 4 10 2 9 9 10 P1分配成功,进入安全序列,分配完成后,将资源还给可利用资源,7、P2: 已分配 1 3 5 4, 还需要 2 3 5 6,当前可利用资源 2 9 9 10足够分配给P2; Process Allocation Need Available(Available-Need) Available+Allocation P2 3 6 10 10 0 0 0 0 0 6 4 4 3 12 14 14 P4分配成功,进入安全序列,分配完成后,将资源还给可利用资源,所以:当前的安全序列为: p0-p3-p4-p1-p2,如果在未分配的时候:p2请求 1 2 2 2 ,从资源池里给他分配,请问可以分配吗?,运行结果:,内存飙升,罪魁祸首竟是死锁,这样检测和处理减少一半加班时间,文章出自:​​石添的编程哲学​​,如有转载本文请联系【石添的编程哲学】今日头条号。

文章版权声明

 1 原创文章作者:cmcc,如若转载,请注明出处: https://www.52hwl.com/22779.html

 2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈

 3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)

 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023年3月5日 上午12:00
下一篇 2023年3月7日 下午10:34