2013-04-02 63 views
2

我想使用類作爲Observer和Observable。這個類將作爲線程運行。在run()方法中,線程將會等待,並且在得到事件線程後會被通知。有示例代碼:觀察者,可觀察和可運行。爲什麼同步塊丟失監視器?

public class Runner { 

    public static void main(String[] args) { 
     MyThread mt = new MyThread(); 
     Controller c = new Controller(); 
     mt.addObserver(c); 
     c.addObserver(mt); 
     Thread t = new Thread(mt); 
     t.start(); 
    } 

} 


public class MyThread extends Observable implements Observer, Runnable { 

    static private Integer op = 0; 

    public void run() { 
     synchronized (this) { 
     while (true) { 
      op++; 
      System.out.println(op + " Thread started"); 
      super.setChanged(); 
      super.notifyObservers(new Object()); 
      op++; 
      System.out.println(op + " Thread send event"); 
      try { 
      op++; 
      System.out.println(op + " Thread wait"); 
      this.wait(); 
      } catch (InterruptedException e) { 
      e.printStackTrace(); 
      } 
     } 
     } 
    } 

    @Override 
    public void update(Observable arg0, Object arg1) { 
     op++; 
     System.out.println(op + " Thread got event"); 
     synchronized (this) { 
     op++; 
     System.out.println(op + " We are in synchronized block!"); 
     this.notify(); 
     } 
    } 

} 


public class Controller extends Observable implements Observer { 

    public void update(Observable arg0, Object arg1) { 
    System.out.println("Controller get and send event"); 
    super.setChanged(); 
    super.notifyObservers(new Object()); 
    } 

} 

Getted輸出爲:

1 Thread started 
Controller get and send event 
2 Thread got event 
3 We are in synchronized block! 
4 Thread send event 
5 Thread wait 

和線程保持鎖定狀態。預期產出:

1 Thread started 
Controller get and send event 
2 Thread got event 
3 Thread send event 
4 Thread wait 
5 We are in synchronized block! 

怎麼回事?爲什麼在顯示器發佈之前我進入同步模塊? P.S.我有一個想法,即將觀察者添加到MyThread對象,可能是我將觀察者添加到線程對象?但我怎麼能做到這一點?

+2

似乎沒有其他線程通知等待線程後 – prasanth

+0

你線程卡在這裏'this.wait();' – prasanth

回答

1

嗯,我認爲你最主要的問題是​​關鍵字類似於一個可重入鎖(http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html)。

這意味着,當您在MyThreadrun方法中時,您將通知Controller。然後這個人調用您的MyThreadupdate,它輸入​​塊(因爲它是可重入的)並完成此方法。之後,Controller.update方法返回並且MyThread.run方法的其餘部分繼續,因此被卡在this.wait()上。

1

設置一個斷點並逐句通過/調試應用程序將幫助您找到導致此行爲的原因。 原因是在線程開始等待之前調用MyThread.update,並且沒有其他線程可以喚醒此線程。你需要第二個線程。

MyThread.run方法中,您將通過以下行通知Controller對象: super.notifyObservers(new Object());

這將調用Controller物體,這反過來又然後調用MyThread對象的update方法(通過通知它)的方法update用於打印同步塊消息。

然後notifyObservers呼叫您的MyThread.run返回,並且只有您的呼叫接通wait方法。

爲了達到您的預期結果,您需要第二個線程在呼叫等待後通知您的MyThread對象。

使用主線程最簡單的例子,需要這些變化:Controller.update

移除通知:

public class Controller extends Observable implements Observer { 
    public void update(Observable arg0, Object arg1) { 
     System.out.println("Controller get and send event"); 
     super.setChanged(); 
     // super.notifyObservers(new Object()); 
    } 
} 

開始MyThread,而不是之後添加的通知,這是從主線程調用。

public static void main(String[] args) { 
    MyThread mt = new MyThread(); 
    Controller c = new Controller(); 
    mt.addObserver(c); 
    c.addObserver(mt); 
    Thread t = new Thread(mt); 
    t.start(); 

    //add the following: 

    try { 
     Thread.sleep(1000); //sleep for a while to make sure MyThread is waiting 
    } catch (InterruptedException ex) { 
     Logger.getLogger(Runner.class.getName()).log(Level.SEVERE, null, ex); 
    } 
    c.notifyObservers(); //notify MyThread 
} 

這將產生以下結果:

1 Thread started 
Controller get and send event 
2 Thread send event 
3 Thread wait 
4 Thread got event 
5 We are in synchronized block! 
6 Thread started 
Controller get and send event 
7 Thread send event 
8 Thread wait 

正如你所看到的,MyThread.run繼續它得到通知