例如,线程A请求锁7,但是锁7这个时候被线程B持有,这时线程A就可以检查一下线程B是否已经请求了线程A当前所持有的锁 。
如果线程B确实有这样的请求,那么就是发生了死锁(线程A拥有锁1,请求锁7;线程B拥有锁7,请求锁1) 。
当然,死锁一般要比两个线程互相持有对方的锁这种情况要复杂的多 。
线程A等待线程B,线程B等待线程C,线程C等待线程D,线程D又在等待线程A 。
线程A为了检测死锁,它需要递进地检测所有被B请求的锁 。
从线程B所请求的锁开始,线程A找到了线程C,然后又找到了线程D,发现线程D请求的锁被线程A自己持有着 。这是它就知道发生了死锁 。
下面是一幅关于四个线程(A,B,C和D)之间锁占有和请求的关系图 。像这样的数据结构就可以被用来检测死锁 。

文章插图
死锁检测
那么当检测出死锁时,这些线程该做些什么呢?
一个可行的做法是释放所有锁,回退,并且等待一段随机的时间后重试 。这个和简单的加锁超时类似,不一样的是只有死锁已经发生了才回退,而不会是因为加锁的请求超时了 。虽然有回退和等待,但是如果有大量的线程竞争同一批锁,它们还是会重复地死锁(编者注:原因同超时类似,不能从根本上减轻竞争) 。
一个更好的方案是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁 。如果赋予这些线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级 。为避免这个问题,可以在死锁发生的时候设置随机的优先级 。
开放调用避免死锁在协作对象之间发生死锁的例子中,主要是因为在调用某个方法时就需要持有锁,并且在方法内部也调用了其他带锁的方法!
如果在调用某个方法时不需要持有锁,那么这种调用被称为开放调用!
我们可以这样来改造:
同步代码块最好仅被用于保护那些涉及共享状态的操作!
class CooperatingNoDeadlock { @ThreadSafe class Taxi { @GuardedBy("this") private Point location, destination; private final Dispatcher dispatcher; public Taxi(Dispatcher dispatcher) { this.dispatcher = dispatcher; } public synchronized Point getLocation() { return location; } public synchronized void setLocation(Point location) { boolean reachedDestination; // 加Taxi内置锁 synchronized (this) { this.location = location; reachedDestination = location.equals(destination); } // 执行同步代码块后完毕,释放锁 if (reachedDestination) // 加Dispatcher内置锁 dispatcher.notifyAvailable(this); } public synchronized Point getDestination() { return destination; } public synchronized void setDestination(Point destination) { this.destination = destination; } } @ThreadSafe class Dispatcher { @GuardedBy("this") private final Set<Taxi> taxis; @GuardedBy("this") private final Set<Taxi> availableTaxis; public Dispatcher() { taxis = new HashSet<Taxi>(); availableTaxis = new HashSet<Taxi>(); } public synchronized void notifyAvailable(Taxi taxi) { availableTaxis.add(taxi); } public Image getImage() { Set<Taxi> copy; // Dispatcher内置锁 synchronized (this) { copy = new HashSet<Taxi>(taxis); } // 执行同步代码块后完毕,释放锁 Image image = new Image(); for (Taxi t : copy) // 加Taix内置锁 image.drawMarker(t.getLocation()); return image; } } class Image { public void drawMarker(Point p) { } }}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 兆 宽带中的“M”是什么意思?
- 绿豆汤为什么煮出来是红色的有毒吗 北方绿豆汤为什么煮出来是红色的
- 蚊子怕空调冷风吗 为什么蚊子怕空调
- 如何自己动手更换运营商宽带光猫,需要注意什么?
- 飞机的轨道是什么样的 飞机飞行的轨道是怎么样的
- 方便面面算不算垃圾食品 请问方便面是属于垃圾食品吗
- 50年代红印圆茶,鼎兴圆茶是什么茶
- |三十多岁女子出轨,起因是老公出国出差,难道就不值得同情嘛
- 柯基和哈士奇配出来的狗是什么样的 哈士奇和主人吵架
- 安化天尖黑茶功效,安化黑茶的含梗量是多少
