4

スレッドが を待たないのはなぜnotify()ですか? スレッドが開始されてから待機プールに移動しますが、その瞬間から実行に進みます。

public class JavaApplication2 {
    public static void main(String [] args) {
       ThreadB b = new ThreadB();
       synchronized(b) {
           b.start();
           try {
              System.out.println("1");
              b.wait();
         } catch (InterruptedException e) {}
          System.out.println("Total is: " + b.total);
       }
     }
 }
  class ThreadB extends Thread {   
    int total;
      @Override
    public void run() {
        synchronized(this) {
            total += 1;
            //notify();
       }
    }
 }
4

6 に答える 6

7

スレッドオブジェクト自体で同期していますが、これは間違った使用法です。何が起こるかというと、死にかけている実行スレッドは常にnotifyそのThreadオブジェクトを呼び出します。Thread.join これに依存します。したがって、自分の行動がある場合とない場合で同じ行動をとる理由は明らかですnotify

解決策:スレッドの調整に別のオブジェクトを使用します。これが標準的な方法です。

于 2013-01-06T21:42:43.143 に答える
1

それ以外のオブジェクトでコードを同期しようとすると、ThreadB決して終了しないことがわかります。これは、 への隠し呼び出しがあるためnotifyです。

これが指定されている場所はどこにもありませんが、スレッドは終了時に自分自身に通知します。joinこれは、メソッドの実装方法において暗黙的です。これはのコードですjoin:

public final synchronized void join(long millis)
throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (millis == 0) {
        while (isAlive()) {
            wait(0);
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

(JDK7ソースコードより)

ご覧のとおり、への呼び出しは、スレッドの終了後に呼び出されるwait呼び出しがどこかにある場合にのみ意味があります。notify同じ呼び出しnotifyにより、プログラムを終了できます。

于 2013-01-06T23:25:55.237 に答える
1

「割り込みと偽のウェイクアップが可能です」という通知まで、待機から戻らないことに依存することはできません。一般に、スレッドが待機している間、待機呼び出しをループでラップする必要があります。

于 2013-01-06T21:20:58.803 に答える
0

同期された{}構造を2つの場所にネストしました。これらの構造は奇妙なことをしているように見えます。スレッドは通知にまったく反応せず、ThreadB(b)が終了したときにのみ再開します。これを削除します:

public class JavaApplication2 {
    public static void main(String[] args) {
        ThreadB b = new ThreadB();
        b.start();
        try {
            System.out.println(" ### Waiting for notify");
            synchronized (b) {
                b.wait();
            }
            System.out.println(" ### Notified");
        } catch (InterruptedException e) {
        }
        System.out.println("### Total is: " + b.total);
    }
}

class ThreadB extends Thread {
    int total;

    @Override
    public void run() {
        total += 1;
        System.out.println(" *** Ready to notify in 5 secs");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
        }
        System.out.println(" *** Notification sent");
        synchronized (this) {
            notify();
        }
        System.out.println(" *** 5 sec post notification");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
        }
        System.out.println(" *** ThreadB exits");
    }
}

上記のコードはおそらく正しく機能します。notify()が存在する場合、メインスレッドは5秒後、ThreadBが終了するというメッセージが表示される前に再開します。notify()がコメントアウトされると、notify()が他のコードから呼び出されるため、メインスレッドは10秒およびThreadBの終了に関するメッセージの後に再開します。Marko Topolnikが、この「舞台裏」のnotify()呼び出しがどこから来たのかを説明します。

于 2013-01-06T21:59:56.943 に答える
0

OCP SE 7 を読みながら、待機/通知操作で同じテストを行っていました。著者に説明を任せるべきだと思います。

于 2016-03-23T03:44:38.640 に答える