粉丝9248获赞6.5万
思索如何定位避免?哈喽,大家好,我是徐树,继续来给大家讲解高频面试题,如何快速的定位以及避免思索。那思索这概念呢,最早是出现在操作系统当中的,在我们句号当中呢,通常指的是现成的思索, 那一旦你的程序发生了现成死锁的话,我们在线上呢,通常是没有特别好的一个办法去应对的,你只能快速的去重启一下你的应用程序,因为如果你不重启的话,就会造成现成的一个堆积,最终导致 om 内存的一个溢出。所以说我们在日常开发当中呢,应该尽量的去避免死锁的发生,最好呢不要产生死锁。 那么如何才能避免死锁呢?以及出现了死锁,在线上如何快速的去定位解决呢?那徐老师来给大家讲一下,那什么是死锁呢?给大家总结一句话,就是在并发下现成,因为相互等待对方的一个资源,导致永久阻塞的这样的一个现象。关于这个问题的详细文字版,我已经整理了一份八十万字的专访秘书 笔记,放在视频的最后面,坚持看完一定对你有帮助。那为了让大家更好的去理解这句话,我给大家写了一个伪代码,那它的功能呢,就是转账,好吧,这里呢有两个账户,一个张三,一个李四,首先呢张三给李四去转五十块钱,李四呢给张三转五十块钱, ok, 那我创建了两个县城,好吧, 那么为了在转账的过程当中保证账户的一个行程安全呢,我们使用了同步锁,锁住了正在转账的这个账户, 那这个肯定要保证他的现场安全,对吧?因为假如说你在转账的过程当中又取钱的话,是不是会出现数据的一个混乱啊?对不对?所以说为了保证现场安全,我们要锁住正在转账的这个账户, 那么李四他的这个账户也是一样的,我们保证现场安全,同样的也要锁住。那么张三转给李四的这个县城呢?他为了保证李四的这个账户的 县城安全呢?同样的他也要锁住李四这个账户,对不对?那此时呢,他就要获取李四这个账户的资源,但是李四他此时是不是已经被这个县城锁住了呀?对吧? 那李四同样的他需要保证张三这个账户的现场安全,他也需要锁住张三,但是此时呢,张三同样的也被这个县城锁住了, ok, 那此时我们就会发现他们就出现了相互等待对方的一个资源,对吧?从而呢导致永久阻塞的这样的一个现象, 能明白,我给大家去运行一下这个代码,好吧,我在这个程序当中呢,呃,给大家运行看一下, ok, 好吧,一个张三,一个李四,然后创建了两个县城,他们呢去调用各自的一个转账方法,那么在这个转账方法当中呢,为了更好的去体现这个思索啊,我给他睡了两秒, 好吧,然后呢互相锁住对方的一个资源, ok, 来给大家运行一下。 好的,我们可以看到,此时呢输出了现成一的 begin, 现成二的 begin, 对吧?但是这个现成的 end 迟迟没有输出,说明什么?说明他们此时呢卡在了这里, 对不对?那这就是县城的一个思索啊,那如果出现在我们线上,我们如何才能快速的定位呢?其实要定位的话也很简单,我们可以打开我们的命令窗口,好吧,当然在 linux 它上面也是一样的去解决啊。首先我们查找一下我们当前这个程序的进程,答是七九四零零,然后结合 g stock 这个命令,打上你当前的这个进程 id 回车。那么此时呢,我们可以看到 fund one 带的 log 找到了一个思索,对不对?并且呢他也把哪两个县城进行思索的这个调用站给你展示出来了,并且从这个集成站当中呢,我们可以 快速的去进行定位,你看啊,他说发生在这个地方等待哪个对象,等待这样的一个对象,对吧?这是他内存的一个地址,这是 tr 这个县城等待这个资源,然后呢,他同时也锁住了这个资源, 然后 t 一呢,它等待这个资源,然后锁住了这个资源,我们会发现 t 二等待的这个资源它是被 t 一锁住的,对不对? t 一等待这个资源,它是被 t 二锁住的, 所以说这就出现了死锁的这样的一个情况,然后通过这里的这个现实账,我们就能够快速的去定位到底是哪一句代码出现的这个问题了。好吧,给他总结一下,你就是怎么样啊? 通过 gps 找到你当前这个程序的进程 id, 然后通过 gee stock 带上你进程 id 呢,去打印出当前正在死锁的这个线程, ok, 当然我们现在虽然知道怎么快速的去定位线上死锁的代码了,但是如何去解决,如何有效的去预防呢?我们不可能说为了解决死锁,我直接把这个等待资源的 把锁直接去掉,对吧?虽然这样死锁是解决了,但是会现成不安全啊,在高并发的一个情况下,我这里的转正金额肯定会出现数据错乱的,所以说我们如何能够保证现成安全的前提下再来解决死锁呢?那我们首先呢需要给大家去讲一下产生死锁的四大因素, 当出现了死锁呢,他会同时满足这四大因素,所以说我们只需要破坏其中的一个因素,就能有效的去解决并且预防死锁。 当然现在网上呢也有很多人去讲这个思索的,解决的这个方案也是基于这四大因素来讲的,但是讲的都非常的抽象啊,其实都是把这个念一遍,具体代码怎么实现,怎么落地,不知道对不对? 所以说徐硕老师呢,希望通过白话,然后再结合代码一个实战呢,带你们去掌握,好吧,那废话不多说,如果有帮助给老师一个三点支持,好吧。首先第一个互斥什么意思呢?就是共享资源只能被一个县城占有,其实就是在我们 代码当中的这个护制锁的一个体现,一定是在我们现实生活就是一个男的,他只能站着一个女朋友, ok, 这就是护制锁。 那第二个因素呢,就是占有且等待,这什么意思呢?就是县城当前至少占有一个资源,并且还想请求其他县城持有的资源,就会造成等待,那这个我们代码同样的也满足,对不对?就是我一个县城等待另外一个县城的资源,就比如说我 a 想要 b 的女朋友, 那必由于使用了物质呢,你必须在外面等待,对不对?那这个时候呢,就会造成占有且等待,这是第二点,第三点,不可抢占,什么意思呢?就是资源只能由只有他的这个县城自愿释放,其他的县城不可强行占有资源。 我们在代码当中使用的是 synchronite 去锁住这个资源,对吧?我被锁的这个资源呢,是无法由另外一个县城去通过代码去释放的,我们 gdk 根本就没有提供这样的代码,所以说不可能能够做到,对不对? 那在我们这个现实生活当中也是一样的,就比如说我 a 想要 b 的女朋友,就说 a 他除了有自己有一个女朋友啊,他还想要 b 的女朋友,但是 a 他不能要求 b 分手,只能由 b 这个现任呢去主动的去释放,就这意思,好吧。 然后呢,第四点,循环等待,也就是我除了 a 想要 b 的女朋友,我 b 呢还想要 a 的女朋友,所以这一出出现了一个循环等待,那在我们单马当中也是一样的,对吧?张三转账想要李四的锁,李四转账呢,想要张三的锁,出现了循环等待, 所以说当出现了思索呢,他会同时满足这四大条件,那我们只需要呢破坏某一个就能解决思索,那徐老师呢?带着你们逐个去破坏,那你在大马当中觉得你哪个适用呢?你就破坏哪一个,好吧,那首先是护翅, 我刚刚说了,体现护士就是护士锁,那你要不使用护士锁的话,你就得去结合你代码的一个业务以及这个功能了,对不对?就比如说我这里的这个代码非常的简单, 就是去计算一下这个账户金额,对不对?那我们比如说我能不能通过这个原子计算奥特曼一个 intake, 对不对?我们通过这个原子计算呢来进行操作,那么这样呢?他就不会有现成安全的问题,对不对?我直接通过原子操作, 这样是不是就 ok 了,对吧?这样呢就解决了现场安全的问题,那我只那我就不需要去锁那个等待的那个资源了,那这就解决了,思索。当然你还可以考虑,比如说能不能用这个 search logo 啊, 对吧?等等等等,比如说用,用这个 cs, 用乐观锁,能不能解决呢?对吧?所以说我们不使用护士锁,肯定呢就不会出现死锁的这样的一个情况, ok, 这是第一个破坏点, 那第二个破坏占有且等待。我们刚说了,一个男的,我除了自己有一个女朋友以外,我还想要其他的 这个男的女朋友,对不对?这就是占有且等待。那我能不能这样搞啊?我两个我都给他占了,我两个我都给他占了。就比如说你 a 不是想要 b 的女朋友吗?我给你占着,对吧? ok, 那你 b 呢?也想要这两个, 那我等你用完之后我再来用。那关键是我在代码当中怎么同时锁住两个字标呢?我们代码好像并没有提供这样的一功能,对不对?我不能说我在星空袋子里面还能同时锁两个吧?好像没有提供这样的功能,对不对?那我们可以通过变通的方式,好吧?来, 我什么意思呢?我给你加一个这个女朋友的,专门的这样的一个管理场所,好吧,我加一个管理场所, ok, 那这个管理场所啊,他只能同时的去服务一个县城,就比如说我 a, 我想要这两个资源,我同时拿到,好吧, ok, 那我这两个资源我就给你,并且呢我给你标记一个已经出去了,好吧,那此时 a, 我想要这两个资源,那不行,因为我这里标记已经出去了, 那你只能呢在外面等着,那我通过自选的方式让你一直在外面等, ok, 我 a 用完这两个资源呢,我给他放回去,我把这个标识给他抹掉,那此时呢 b 就可以拿到这两个资源,那么自选呢就结束, 那在他代码当中怎么实现呢?也非常的简单,我这里呢就有一个这个资源的管理者,好吧,那么他有一个例子呢,用来存这两个资源,有一个 app 方法,好吧,然后呢有个福利方法去释放这两个资源,那在我们转账的时候啊,在我们转账的时候,我就先 通过某一个县城先进来,先去调这个 app 方法,也就是说呢,先去拿到这两个资源,如果资源拿到了,正常的执行下面的代码, ok, 那如果在县城一执行的过程当中,我县城二进来,那么他此时呢会 app 会 返回 force, 他拿不到这两个资源,好吧,因为我这个历史的里面呢,已经有这两个资源了,他会判断已经存在了,会 return force, 那么我这里呢会一直的自悬下去, 直到我现成一用完这两个资源给他释放掉,那么我现成二呢,才能拿到这个资源,并且正常的往下面去执行, ok, 那么这是破坏占有且等待, 那第三点,不可抢占,这我们刚刚说的对吧?我虽然想要另外一个人的女朋友,但是我不能要求他们分手, 那么我们的星空奈子锁也是一样的,对不对?我不能去设置其他锁住的这个对象呢,进行释放,我只能用完了之后它自动释放,那我们能不能用一种变通的方式啊?比如说用这个洛克,大家用过没有?洛克呢,他有一个超时的机制,我通过洛克我锁住的这个资源啊,我可以设置超时,比如说我这里两秒, 如果两秒还没有释放,他将自动释放,能不能理解?那么这样呢?就能有效的去避免这个死锁,就比如说什么意思呢?我虽然对吧,我 a 不能要求你 b 主动放手, 但是呢我系统呢,给你们设置一个规则,你们这个热恋期啊,也就是你们在一起的时间只能两个月,好吧,那我 a, 我有一个女朋友,那此时我还想要 b 的女朋友 ak, 我等两个月,我等两个月,对吧?两个月过了之后我拿到,然后处理完呢,我就走了, 然后 b 也是这样的,我要你 a 的资源,那我一样的等待两个月,两个月过了我拿到资源,然后处理完直接走人,好吧,就那么这就是 破坏,不可抢占,虽然我们无法释放另外一个被锁住的资源,但是可以通过洛克去设置他的这个超时, ok, 然后呢第四点,循环等待,那循环等待,我们刚才已经说了,对不对?他们之间交叉的这样打, 互相等待,那我怎么解决这个问题呢?那我能不能这样,我让他们有序的等待,比如我现成 a, 我要这两个资源,我给他标做一个标记,我有序的去锁这两个资源,那我 b 我要这两个资源,我一样的按照你之前标记的这个资源呢 去锁这些资源。那么此时在高并发的一个情况下,我 a 首先呢拿到这个资源一,那 b 我想要资源一,我大不了就是等待堵塞嘛,对吧?等 a 处理完了,这个资源一释放了,我就能拿到,对吧?然后同样的他去获取资源二,我这我这个资源二,同样的我这个现成 b 想要资源二,我同样的会等待,对不对?那么现成 a 他用完了,他就释放了,释放完之后呢,我就可以拿到这两个资源来进行处理, 对不对?那在我们代码当中呢,实现起来也非常的简单,我在这里,我在这里创建这两个账户的时候呢,就有个 id, 那么我再去锁对象的时候,我就通过这两个 id 给他们重新的去排一下顺序,就比如说 id 小的我给他排在前面, id 大的我给他排在后面,那么我锁的时候呢,就按照这里的这个顺序来进行锁, 那么就不会出现死锁的一个情况下,那这就是产生死锁的四大因素,以及破坏这四大因素的方式。破坏这四大因素确实能够有效的去预防死锁, 但是呢,我们刚刚其实也看到通过这种方式呢,他其实会抑制我们系统的一个新能,对吧?会使我们应用的一个吞吐量呢降低,因为大部分的一个情况下呢,除了这个 破坏护士,对吧?基本其他的这种都变成了创新,对不对?就比如说这个战友节,等待我同时获得这两个资源,对吧?那另外一个新人就等等就得等待了,就变变成创新了,然后呢不可抢账也是一样的,对吧?我虽然设置了这个超时间,但是我依然 需要等待这个你设置的超时间循环等待也是一样的,我虽然按照顺序去给你加锁,但是呢,你在加锁的过程当中,我们另外一个县城依然无法获得你被锁的这个资源,对不对?但是有效的去解决了死锁, 所以说我们在现在这个实际开发当中,可以利用这种方式呢去预防思索,但是并不会百分之百的这样去做,因为哪怕有时候我们应用当中同时满足了这四大因素,也并不是说一定会出现思索,所以我们希望的是什么?能够 避免思索的出现,而不是说完全杜绝,好吧,破坏这四,这个四的因素就完全杜绝了,而要有效的一定几率的避免的话,大家可以去了解一个叫做银行加的算法,好吧,通过这个银行加算法呢,就能够去有效的一定几率的去避免这个思索, 那并且呢,我们的这个系统的吞吐量性能也能得到一定的保障,好吧,这个银行家算法我就不在这里展开来说了,同学们如果有兴趣呢,可以给徐老师点一波赞,如果赞这个超过了一千呢,我就给大家呢去讲一讲这个银行家算法是怎么回事? ok, 然后那么这个思索的解决 定位第二个呢,破坏我们的这个四大因素,从而呢完全的去杜绝我们的思索。第三,我们其实可以通过银行加算法呢,有一定的几率的去避免思索,从而既能保证我们系统的吞吐量性能,对吧?又能去避免思索。 ok, 这三个知识点希望大家能够掌握,如果对你有帮助呢?可以三连支持一下,那么老师这个视力当中的代码也可以加我的资料来进行获取。 nice。