如何避免死锁,那就把死锁产生的原因及必要条件避免了,问题自然而然就解决了。
那么先看死锁产生的4个必要条件
1、互斥: 某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。
2、占有且等待: 一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。
3、不可抢占: 别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。
4、循环等待: 存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源。
当以上四个条件均满足,必然会造成死锁,发生死锁的进程无法进行下去,它们所持有的资源也无法释放。这样会导致CPU的吞吐量下降。所以死锁情况是会浪费系统资源和影响计算机的使用性能的。那么,解决死锁问题就是相当有必要的了。
如何分别解决这四个条件
互斥
互斥是非常容易解决的 使用ThreadLocal就能解决 ,互斥产生的本质原因就是多个线程要同时竞争一个资源,那么我们给每个线程都分配一个自己管理的资源不就好了。
但是使用ThreadLocal要特别注意 即时使用remove方法,否贼会引起内存泄漏。因为ThreadLocal底层是一个ThreadLocalMap,他的key是一个弱引用,而value呢确是强引用意味着value不会被GC清除,而key是弱引用如果外部没有再对key强引用的话key将被回收,被强引用的value将找不到与其对应的映射关系,那么便会发生内存泄漏。remove方法会找到这些key已经被回收的value并将他们回收。
占有且等待
破环占有且等待方法与循环等待类似,可以采取一次性获取全部需要资源的方式来解决。
不可抢占
那就是先获取锁,如果自己发现进一步申请不到其他的资源(锁),那么就释放自己已经获得的锁,那么也就不会继续死锁下去了。这个条件对应c封装的synchronized关键字同样是不行的,但是基于juc Lock写的程序还可以调用lockInterruptibly方法处理。
循环等待
这也是一个比较容易解决的,我们可以让线程对资源的加锁按照一定统一的顺序。比如如果有要AB两个资源的两个线程,那我们就都先拿A 再拿 B这样想获得B就一定要先得到A 就避免了循环等待的问题。起始说到底这种方法也是一种锁的粗化。