
在某些情况下,可以避免死锁. 本文将介绍三种避免死锁的技术:
1. 锁定顺序
2. 锁定时间限制
3. 死锁检测
锁定顺序

当多个线程需要相同的锁,但以不同的顺序锁定它们时,很容易发生死锁.
如果可以确保所有线程以相同的顺序获取锁,则不会发生死锁. 看这个例子:
Thread 1: lock A lock B Thread 2: wait for A lock C (when A locked) Thread 3: wait for A wait for B wait for C
如果线程(例如线程3)需要一些锁,则它必须以一定顺序获取锁. 只有获得序列前面的锁之后,才能获得后面的锁.
例如,线程2和线程3只能在获取锁A之后尝试获取锁C(获取锁A是获取锁C的必要条件). 因为线程1已经拥有锁A,所以线程2和3需要等待直到锁A被释放. 然后他们必须成功锁定A才能尝试锁定B或C.

顺序锁定是一种有效的防止死锁的机制. 但是,此方法要求您事先知道所有可能使用的锁(并对这些锁进行正确排序),但是有时这是不可预测的.
锁定时间限制
另一种避免死锁的方法是在尝试获取锁时添加超时期限. 这意味着,如果在尝试获取锁的过程中超过了此时间限制,则线程将放弃锁请求. 如果线程在给定的时间内未成功获取所有必需的锁,它将回滚并释放已获取的所有锁,然后等待随机的时间段再尝试. 这种随机的等待时间使其他线程有机会尝试获取相同的锁,并允许应用程序在未获取锁的情况下继续运行(在锁超时之后java多线程避免死锁,您可以继续运行以执行其他操作,然后继续执行)返回并重复之前的“锁定”逻辑. )
下面是一个示例,该示例显示了一个场景,其中两个线程尝试以不同的顺序获取相同的两个锁,先退后再在发生超时后重试:
Thread 1 locks A Thread 2 locks B Thread 1 attempts to lock B but is blocked Thread 2 attempts to lock A but is blocked Thread 1's lock attempt on B times out Thread 1 backs up and releases A as well Thread 1 waits randomly (e.g. 257 millis) before retrying. Thread 2's lock attempt on A times out Thread 2 backs up and releases B as well Thread 2 waits randomly (e.g. 43 millis) before retrying.

在上面的示例中,线程2重试以比线程1早200毫秒锁定,因此它可以首先成功地获得两个锁定. 此时,线程1尝试获取锁A并处于等待状态. 当线程2结束时,线程1也可以成功获得这两个锁(除非线程2或其他线程程1成功获得这两个锁之前获得了其中一些锁).
应该注意的是,由于锁定超时,我们不能假定在这种情况下发生了死锁. 这也可能是因为获得锁的线程(导致其他线程超时)需要很长时间才能完成其任务.
此外,如果有许多线程同时争用同一批资源,即使存在超时和回滚机制,也可能仍然导致这些线程反复尝试,但从未获得锁. 如果只有两个线程,并且重试超时设置在0到500毫秒之间,则可能不会发生这种现象,但是如果是10或20个线程,情况就不同了. 因为这些线程等待相等的重试时间的可能性要高得多(或者接近,以至于它们会引起问题). (超时和重试机制是为了避免同时发生竞争,但是当线程很多时,两个或多个线程的超时时间很可能相同或接近,因此即使存在竞争,超时稍后,因为超时时间相同,他们将同时开始重试,从而导致新一轮的竞争并带来新的问题. )
此机制存在问题. 您无法在Java中为同步块设置超时. 您需要创建自定义锁或使用Java 5中java.util.concurrent包下的工具. 编写自定义锁类并不复杂,但这超出了本文的范围.
死锁检测

死锁检测是一种更好的防止死锁的机制. 主要针对无法实现顺序锁定且锁定超时不可行的场景.
每当线程获得锁时,它将被记录在与该线程和锁相关的数据结构(映射,图形等)中. 此外,每当线程请求锁定时,也需要将其记录在此数据结构中.
当线程未能请求锁时,线程可以遍历锁关系图以查看是否发生死锁. 例如,线程A请求锁7,但此时锁7由线程B持有. 这时,线程A可以检查线程B是否请求了线程A当前持有的锁定. 如果线程B确实有这样的请求,则发生了死锁(线程A拥有锁1并请求锁7;线程B拥有锁. 7java多线程避免死锁,并请求锁定1).
当然,死锁通常比两个线程持有彼此的锁要复杂得多. 线程A等待线程B,线程B等待线程C,线程C等待线程D,线程D再等待线程A. 为了使线程A检测死锁,它需要逐步检测B所请求的所有锁. 从线程B所请求的锁开始,线程A找到线程C,然后找到线程D,并找到线程D所请求的锁. 由线程A本身持有. 这是当它知道发生死锁的时候.
那么当检测到死锁时这些线程会做什么?
一种可行的方法是释放所有锁,回滚并等待随机的一段时间,然后重试. 这类似于简单的锁定超时. 区别在于它仅在发生死锁时回滚,而不是因为锁定请求超时. 尽管存在回滚和等待,但是如果有大量线程竞争同一批锁,它们仍将反复死锁.
一种更好的解决方案是为这些线程设置优先级,并让一个(或几个)线程回退. 其余线程继续保持所需的锁,就好像没有死锁发生一样. 如果分配给这些线程的优先级是固定的,则同一批线程将始终具有更高的优先级. 为避免此问题,可以在发生死锁时设置随机优先级.
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-273983-1.html
女性
泄浊屎
包括军舰
这需要胆量和魄力