什么是死锁:
两个或者多个线程永远阻塞,相互等待对方的锁
是并发下一组互相竞争资源的线程因互相等待导致永久阻塞的现象
例:
解释:
线程a占用对象锁1,线程b占用对象锁2
线程a需要继续占用对象锁2才能往下执行,所以线程a需要等待线程b释放对象锁2
线程b需要继续占用对象锁1才能往下执行,同样也需要线程a释放对象锁1
由于这2个线程都不释放自己已经占用的锁,所以这2个线程会处于无限等待状态
通俗意:
为了让神灯进入封印,男孩用出了禁术-死锁
神灯: “恭喜你捡到了我,我可以实现你2个愿望,请说出的你2个愿望”
男孩: “请你实现我的第2个愿望”
神灯:“好的,然后呢?”
男孩: “请你实现我的第1个愿望”
神灯进入了死锁状态,成功封印,再也不能完成实现2个愿望的任务
产生死锁4大因素:
互斥:共享资源只能被一个线程占用-互斥锁
占有且等待:线程当前占有至少一个资源并还想请求其它线程持有的其它资源就会造成等待-等待对方释放资源
不可抢占:资源只能由持有它的线程自愿释放,其它线程不可强行占有该资源-无法释放对方资源
循环等待:线程A等待线程B占有的资源,线程B等待线程A占有的资源,就是循环等待-2个线程互相等待
解决死锁:
不能直接去去掉死锁,这样不能保证线程安全
只需要破坏产生死锁4大因素的其中一个因素,就能有效的去解决并且预防死锁
破坏互斥:
例如代码是计算账户金额,那就可以通过原子计算来进行操作,那这样就不会有线程安全问题
或是使用乐观锁,只要不用互斥锁那就不会出现死锁的情况
破坏占有且等待:
可通过占有多个解决;例用循环条件判定list内是否有,没有时传入2个资源,有时返回false拒绝再进入
破坏不可抢占:
用lock锁,利用其超时的机制设置超时;
例:设置2s,如果2s还没有释放它将自动释放
破坏循环等待:
让其有序的等待即可;
例:线程A先锁1,再锁2,进行标记;然后线程B根据标记也先锁1,再锁2
这样能预防死锁,破坏的话就完全杜绝了;
而要有效的一定几率的避免的话,可以了解下银行家算法