首页 > 解决方案 > 扎实的 Java 开发人员中的 Java 死锁示例

问题描述

没看懂《扎扎实实的java开发者》一书中的死锁例子。怎么会出现这种僵局?

乍一看,这段代码看起来很合理。您有两个更新被发送到不同的线程,每个更新都必须在备份线程上得到确认。这似乎不是一个太古怪的设计——如果一个线程出现故障,那么另一个线程可能会继续运行。如果你运行代码,你通常会看到一个死锁的例子——两个线程都将报告接收到更新,但都不会确认接收到它们作为备份线程的更新。这样做的原因是每个线程都需要另一个线程在确认方法可以进行之前释放它持有的锁。

下面是来自代码清单 4.2 的一个死锁示例

public class MicroBlogNode implements SimpleMicroBlogNode {
private final String ident;

public MicroBlogNode(String ident_) {
    ident = ident_;
}

public String getIdent() {
    return ident;
}

public synchronized void propagateUpdate(Update upd_, MicroBlogNode
        backup_) {
    System.out.println(ident + ": recvd: " + upd_.getUpdateText()  + " ; backup: " + backup_.getIdent());
    backup_.confirmUpdate(this, upd_);
}

public synchronized void confirmUpdate(MicroBlogNode other_, Update
        update_) {
    System.out.println(ident + ": recvd confirm: " + update_.getUpdateText() + " from " + other_.getIdent()k);
}

public static void main(String[] args) {
    final MicroBlogNode local = new MicroBlogNode("localhost:8888");
    final MicroBlogNode other = new MicroBlogNode("localhost:8988");
    final Update first = getUpdate("1");
    final Update second = getUpdate("2");

    new Thread(new Runnable() {
        public void run() {
            local.propagateUpdate(first, other);
        }
    }).start();

    new Thread(new Runnable() {
        public void run() {
            other.propagateUpdate(second, local);
        }
    }).start();
}

标签: javaconcurrency

解决方案


第一个线程启动,local.propagateUpdate被调用,local现在被锁定,因为方法是同步的。

几乎同时,第二个线程被启动,other.propagateUpdate被调用并且实例other也因为同样的原因被锁定。

两个线程都愉快地打印文本。在第一个线程中,local实例尝试通过调用实例与另一个线程确认confirmUpdateotherother仍被第二个线程锁定 - 该方法尚未返回。

在第二个线程中,other实例尝试调用confirmUpdatelocal实例,但该实例也被锁定 - 这次是由第一个线程锁定的。

local并且other都在等待对方释放他们的锁,并且永远无法解决问题:这是死锁。


推荐阅读