2013-04-02 1 views
2

Я пытаюсь использовать класс как Наблюдатель и Наблюдаемый. Этот класс будет запущен как поток. В методе 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, может быть, я добавлю наблюдателя в объект Thread? Но как я мог это сделать?

+2

Кажется, нет никакого другого потока, чтобы уведомить нить ожидания – prasanth

+0

Ваш thread застрял здесь 'this.wait();' – prasanth

ответ

1

Ну, я думаю, что главное, что вы натыкаетесь на то, что ключевое слово synchronized напоминает блокировку реентера (http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html).

Это значит, что вы находитесь в вашем MyThread 's run способ, которым вы изведете Controller. Затем этот вызов вызывает update вашего MyThread, который входит в блок synchronized (поскольку он является реентерабельным) и завершает этот метод. После этого возвращается метод Controller.update, и остальная часть вашего метода MyThread.run продолжается, таким образом, застревает на this.wait().

1

Установка точки останова и переключение/отладка приложения поможет вам найти причину такого поведения. Причина в том, что MyThread.update вызывается до того, как поток начинает ждать, и нет другого потока, чтобы разбудить эту тему. Вам понадобится второй поток.

В способе MyThread.run вы сообщаете объект Controller с этой строкой: super.notifyObservers (новый объект());

Это вызывает update метод Controller объекта, который, в свою очередь, затем вызывает update метод MyThread объекта (путем уведомления его), который печатает сообщение блок синхронизированный.

После этого звонок notifyObservers возвращается в ваш MyThread.run, и только после этого вы достигнете своего вызова метода wait.

Чтобы достичь ожидаемого результата, вам понадобится второй поток, чтобы уведомить ваш объект после того, как вы вызвали wait.

Самый простой пример использования основного потока требует, чтобы эти изменения:

Удалить уведомление в 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 продолжается после того, как он получает уведомление о

Смежные вопросы