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

}

得到的输出是:

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!

怎么了?为什么我在监视器释放之前进入同步块?PS 我有一个想法,问题是将观察者添加到 MyThread 对象,我可能会将观察者添加到 Thread 对象吗?但我怎么能做到这一点?

4

2 回答 2

1

好吧,我认为您遇到的主要问题是synchronized关键字类似于可重入锁(http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html)。

这意味着,当您在您MyThreadrun方法中时,您正在通知Controller. 然后这个调用updateMyThread的进入synchronized块(因为它是可重入的)并完成这个方法。之后,该Controller.update方法返回并且您的方法的其余部分MyThread.run继续,因此卡在this.wait().

于 2013-04-02T14:14:45.517 回答
1

设置断点并单步执行/调试应用程序将帮助您找到导致此行为的原因。原因是MyThread.update在线程开始等待之前调用,并且没有其他线程唤醒这个线程。您将需要第二个线程。

MyThread.run方法中,您Controller使用以下行通知对象: super.notifyObservers(new Object());

这会调用对象 的update方法,然后对象的方法会调用(通过通知它)打印同步块消息的对象的方法。ControllerupdateMyThread

然后notifyObservers你的调用MyThread.run返回,然后你才能调用该wait方法。

为了达到您的预期结果,您需要第二个线程MyThread在您调用 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收到通知后继续

于 2013-04-02T14:18:38.600 回答