面试题答案
一键面试死锁产生原因
当线程A获取了锁L1,此时线程B获取了锁L2,然后线程A尝试获取锁L2,由于锁L2被线程B持有,线程A进入等待状态;而线程B尝试获取锁L1,由于锁L1被线程A持有,线程B也进入等待状态。两个线程相互等待对方释放锁,从而形成死锁。
解决方案及优缺点
- 按照固定顺序获取锁
- 方案:无论是线程A还是线程B,都先获取锁L1,再获取锁L2。这样就不会出现相互等待的情况。
- 优点:简单直接,易于理解和实现,不需要引入额外复杂的机制。
- 缺点:可能会导致某些线程等待时间过长,例如如果线程B需要先处理与锁L2相关的紧急任务,但由于要遵循固定顺序先获取锁L1,可能会延迟任务处理。
- 使用超时机制
- 方案:在线程获取锁时设置一个超时时间。例如线程A获取锁L2时,如果在一定时间(如5秒)内没有获取到,则释放已获取的锁L1,并等待一段时间后重新尝试获取锁L1和锁L2。线程B同理。
- 优点:可以在一定程度上避免死锁无限期持续下去,即使出现死锁倾向,也能通过超时恢复。
- 缺点:增加了代码复杂度,需要合理设置超时时间。如果超时时间设置过短,可能导致线程频繁重试获取锁,降低系统性能;如果设置过长,死锁可能持续较长时间才被解除。
- 使用资源分配图算法检测死锁
- 方案:维护一个资源分配图,记录每个线程当前占用的锁以及请求的锁。定期(或在每次获取锁操作时)运行死锁检测算法(如银行家算法的变体),如果检测到死锁,选择一个线程作为牺牲品,释放其持有的锁,让其他线程继续执行。
- 优点:可以精确检测到死锁,并采取措施解除死锁,能更灵活地应对复杂的死锁场景。
- 缺点:实现复杂,资源分配图的维护和死锁检测算法的运行都需要额外的计算资源和时间开销,对系统性能有一定影响。