这个例子中的死锁在哪里?

时间:2014-01-06 14:52:47

标签: java concurrency thread-synchronization

我目前正在阅读The Well-Grounded Java Developer一书中有关并发的部分,这个特定的代码示例演示了块并发应该死锁,但据我所知,它并没有。这是代码:

public class MicroBlogNode implements SimpleMicroBlogNode {

    private final String ident;

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

    public String getIdent(){
        return ident;
    }

    public static Update getUpdate(String _name){
        return new Update(_name);
    }

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

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

    public static void main(String[] args) {
        final MicroBlogNode local = new MicroBlogNode("localhost");
        final MicroBlogNode other = new MicroBlogNode("remotehost");
        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();
    }
}

当我运行它时,我得到以下输出:

localhost: received: 1 ; backup: remotehost
remotehost: received confirm: 1 from localhost

remotehost: received: 2 ; backup: localhost
localhost: received confirm: 2 from remotehost

这本书说如果你运行代码,你通常会看到一个死锁的例子 - 两个线程都会报告接收更新,但是两个都不会确认收到更新 他们是备用线程。原因是每个线程都要求另一个线程在确认方法可以进行之前释放它所持有的锁。

据我所知,情况并非如此 - 每个线程确认接收到它们是备份线程的更新。

提前致谢。

2 个答案:

答案 0 :(得分:2)

这看起来像时间。您的输出显示localhost线程已在remotehost(其他)线程启动之前完成。

尝试在System.out之后的propogateUpdate方法中放置一个Thread.sleep(1000)

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

这应该会造成僵局。

答案 1 :(得分:1)

local尝试拨打同一个电话时,confirmUpdateother上调用线程操作时,会发生死锁。因此,死锁发生在此操作顺序之后

  1. Local通过调用propagateUpdate来锁定自己,因为声明它是synchronized(请参阅Synchronized Member Function in Java
  2. '其他'通过调用propagateUpdate
  3. 锁定自己
  4. Local尝试获取Other上的锁定以致电confirmUpdate,但由于Other已被锁定在另一个帖子中,因此无法锁定。
  5. Other尝试做同样的事情并因同样的原因失败。
  6. 如果它确实有效,那可能是因为它发生得如此之快。再运行几次。线程问题在您希望它们工作时永远不会起作用。