面试题答案
一键面试死锁产生的四个必要条件
- 互斥条件:资源在同一时刻只能被一个线程占用。例如,打印机资源在某一时刻只能被一个打印任务(线程)使用。
- 占有并等待条件:一个线程已经持有了至少一个资源,但又请求新的资源,且在等待新资源分配的过程中,不释放已持有的资源。比如线程A持有资源R1,又请求资源R2,在等待R2的过程中,不释放R1。
- 不可剥夺条件:线程已获得的资源,在未使用完之前,不能被其他线程强行剥夺,只能由该线程自己释放。例如线程B获得了数据库连接资源,在它使用完该连接之前,其他线程不能强行夺走这个连接。
- 循环等待条件:存在一个线程集合{T1, T2, …, Tn},其中T1等待T2持有的资源,T2等待T3持有的资源,…,Tn等待T1持有的资源,形成一个循环等待链。
死锁检测
- 资源分配图算法:通过构建资源分配图,图中节点表示线程和资源,边表示资源的请求和分配关系。使用算法(如深度优先搜索)检查图中是否存在环,若存在环则表示可能存在死锁。
- 超时检测:为每个线程的资源请求设置一个超时时间,如果线程在规定时间内未能获取到所需资源,则认为可能发生死锁,并采取相应措施,如终止相关线程。
代码层面避免死锁
- 资源分配顺序:对所有资源进行编号,所有线程按照相同的顺序请求资源。例如,线程A和线程B都先请求资源R1,再请求资源R2,这样可以避免循环等待。
- 资源一次性分配:线程在启动时一次性请求它所需要的所有资源,而不是逐步请求。如果一次性无法分配所有资源,则该线程不占用任何资源,这样可以避免占有并等待的情况。
- 使用超时机制:如上述检测方法中的超时检测,在代码中为资源请求设置超时。若超时未获取到资源,线程释放已持有的资源并重新尝试。
- 引入资源分配器:创建一个资源分配器对象,负责管理资源的分配和回收。线程向资源分配器请求资源,资源分配器通过合理的调度算法避免死锁。