2014-01-06 23 views
2

我目前正在阅读The Good-Grounded Java开发人员书籍中有关并发的部分,这个演示块并发性的代码示例应该会死锁,但据我所知,它并不会。下面的代码:这个例子中的死锁在哪里?

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 

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

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

在此先感谢。

+3

你确定这是书中的例子吗?向我们展示'Update'类。 –

+0

getUpdateText方法在哪里? – wheaties

回答

1

当您的local调用confirmUpdate上的线程操作时other正在尝试进行相同的调用时发生死锁。因此,死锁发生下列操作的这个顺序调用propagateUpdate由于它是​​声明

  1. Local锁本身(见Synchronized Member Function in Java
  2. “其他”锁本身通过调用propagateUpdate
  3. Local尝试获取锁Other拨打confirmUpdate但不能自Other已被锁定在另一个线程。
  4. Other试图做同样的事情,并出于同样的原因失败。

如果它真的在工作,那可能是因为它发生得太快了。再运行几次。当你希望他们工作时,线程问题将无法工作。

+0

多次重新运行它,我设法使代码死锁。 – user283188

+0

@ user283188太棒了!这是一个典型的“饥饿”问题,其中一个线程试图使用另一个线程当前正在使用的资源,但无法放弃。 – wheaties

2

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

尝试把一个了Thread.sleep(1000)在propogateUpdate方法的System.out

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_); 
} 

这之后要强迫一个僵局。