2013-01-23 33 views
4

我看不到以下代码如何产生看起来违反对象锁的定义的输出。当然,只有一个线程应该被允许打印“获得的锁定”消息,但它们都是?使用内部锁进行块输入

class InterruptThreadGroup { 
    public static void main(String[] args) { 
     Object lock = new Object(); 
     MyThread mt1 = new MyThread(lock); 
     MyThread mt2 = new MyThread(lock); 
     mt1.setName("A"); 
     mt1.start(); 
     mt2.setName("B"); 
     mt2.start(); 
     try { 
      Thread.sleep(2000); 
     } catch (InterruptedException e) { 
     } 
     // Thread.currentThread().getThreadGroup().interrupt(); 
    } 
} 

class MyThread extends Thread { 
    private Object lock; 

    public MyThread(Object l) { 
     this.lock = l; 

    } 

    public void run() { 
     synchronized (lock) { 
      System.out.println(getName() + " acquired lock"); 
      try { 
       lock.wait(); 
      } catch (InterruptedException e) { 
       System.out.println(getName() + " interrupted."); 
      } 
      System.out.println(getName() + " terminating."); 
     } 
    } 
} 
+0

不是一个好主意来扩展线程类。你应该实现可运行的接口。 – Arpit

回答

7

这是因为调用lock.wait()会释放锁,从而允许第二个线程进入同步块。从javadoc

提取这款显示器并等待线程释放所有权,直到另一个线程通知等候在这个对象监视器上或者通过notify方法或notifyAll方法的调用醒来。该线程然后等待,直到它可以重新获得监视器的所有权并恢复执行。

需要注意的是有你的代码的一些问题,如:

  • 你不应该等待一段时间循环外
  • 没有通知任何地方,所以你的等待会天长地久
  • 最好让您的任务实现Runnable并将其作为参数传递给Thread的构造函数,而不是直接扩展Thread。
+1

+1我会补充说OP正在锁定一个非最终字段,并且没有正在检查的状态来确定是否需要wait()或虚假地唤醒。 –

0

要么你应该使用同步块或等待呼叫。一起使用它们是行不通的。如果您使用等待调用,则锁定由同步块中的对象释放。

因此,删除行lock.wait,你的程序将按你的意愿工作。同步块将自动处理所有锁定。

如果您使用等待,则必须使用通知。

以下是有关这个好螺纹:Why must wait() always be in synchronized block