线程死锁了解吗?该如何避免?

死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的互相等待的现象,在无外力作用的情况下,这些线程会一直相互等待而无法继续运行下去。

javathread-47.png

那么为什么会发生死锁呢?死锁的产生必须满足以下四个条件:

  • 互斥条件:线程对已经获取到的资源进行独占性使用,即资源同时只能被一个线程占用。如果有其他线程请求获取该资源,请求者必须等待,直到占有资源的线程释放该资源。
  • 请求并持有条件:线程已经持有至少一个资源,并且提出了新的资源请求,但新资源已被其他线程占用,因此当前线程会被阻塞,但同时并不释放已经获取的资源。
  • 不可剥夺条件:线程获取到的资源在自己使用完之前不能被其他线程抢占,只有在使用完毕后才能由线程自己释放该资源。
  • 环路等待条件:在发生死锁时,必然存在一个线程-资源的环形链,即线程集合 {T0,T1,T2,…… ,Tn} 中,T0 正在等待 T1 占用的资源,T1 正在等待 T2 占用的资源,……,Tn 在等待已被 T0 占用的资源。

要如何避免死锁呢?关键在于破坏死锁发生的至少一个条件。

  • 互斥条件是无法破坏的,因为锁的目的就是实现互斥。但是其他三个条件是可以被破坏的,那么如何做呢?
  • 对于"请求并持有"条件,可以一次性请求所有需要的资源,避免分阶段地请求资源。
  • 对于"不可剥夺"条件,在占有部分资源的线程进一步申请其他资源时,如果无法获得资源,可以主动释放已占有的资源,从而破坏不可剥夺性。
  • 对于"环路等待"条件,可以通过按顺序申请资源来预防。具体而言,资源可以有一个线性顺序,在申请资源时按照顺序先申请序号较小的资源,然后再申请序号较大的资源,这样就消除了环路的可能性。

标签: java, Java面试题, Java问题合集, Java编程, Java问题精选, Java常见问题