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ます。これは、ブロックに入るupdateyour のを呼び出し(再入可能であるため)、このメソッドを完了します。その後、メソッドが返され、メソッドの残りの部分が続行されるため、.MyThreadsynchronizedController.updateMyThread.runthis.wait()

于 2013-04-02T14:14:45.517 に答える
1

ブレークポイントを設定し、アプリケーションをステップ実行/デバッグすると、この動作の原因を見つけるのに役立ちます。その理由はMyThread.update、スレッドが待機を開始する前に が呼び出され、このスレッドをウェイクするスレッドが他にないためです。2 番目のスレッドが必要になります。

このMyThread.runメソッドでは、次の行でオブジェクトに通知していControllerます: super.notifyObservers(new Object());

これupdateにより、オブジェクトのメソッドが呼び出され、オブジェクトはオブジェクトのメソッドを(通知することによって)Controller呼び出し 、同期されたブロック メッセージを出力します。updateMyThread

次に、notifyObservers呼び出しが返されてから、メソッドMyThread.runへの呼び出しに到達します。wait

期待される結果に到達するにMyThreadは、wait を呼び出した後にオブジェクトに通知するための 2 番目のスレッドが必要です。

メイン スレッドを使用する最も単純な例では、次の変更が必要です。

の通知を削除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 に答える