0

wait() および notifyAll() メソッドについて少し質問があります。コードは 2 つのスレッドの「レース」をシミュレートしています。

コードを見てみましょう - 問題は、notifyAll() メソッドが待機中のスレッドで何もせず、main メソッドが最初にロックを取得することです...簡単な解決策は、遅延を設定することです (コメント行を参照)。しかし、それは悪い習慣です。この問題の良い解決策は何ですか? wait/notifyAll/join メソッドのみを使用したい。

public class TestThreads {
  public static void main(String[] args) throws InterruptedException {
    System.out.println("_start main");
    Object lock = new Object();
    Thread t1 = new Thread(new Car("Red car", lock));
    Thread t2 = new Thread(new Car("Black car", lock));
    t1.start();
    t2.start();
    //Thread.sleep(10L);
    synchronized (lock){
      System.out.println("Let`s go!");
      lock.notifyAll();
    }
    t1.join();
    t2.join();
    System.out.println("_exiting from main...");
  }
}

class Car implements Runnable {
  private final String name;
  private final Object lock;

  public Car(String name, Object lock) {
    this.name = name;
    this.lock = lock;
  }

  @Override
  public void run() {
    int distance = 100;
    synchronized (lock){
      try{
        System.out.println(name + " waiting...");
        lock.wait();
      }catch (InterruptedException e){
        e.printStackTrace();
      }
    }
    System.out.println(name + " started...");
    while (distance != 0){
      try{
        Thread.sleep((long) (100 * Math.random()));
      }catch (InterruptedException e){
        e.printStackTrace();
        break;
      }
      distance--;
      if (distance % 20 == 0 && distance != 0){
        System.out.println(name + " " + distance+ " miles left");
      }

      else if (distance == 0){
        System.out.println(name + " finished race!!!");
      }
    }
    System.out.println("_exiting from thread of " + name + " move simulation...");
  }
}

PS。私の悪い英語でごめんなさい。

回答ありがとうございます。それで、この解決策はより良いですか?

public class TestThreads {
  public static void main(String[] args) throws InterruptedException {
    System.out.println("_start main");
    LightSignal lock = new LightSignal();
    Thread t1 = new Thread(new Car("Red car", lock));
    Thread t2 = new Thread(new Car("Black car", lock));
    t1.start();
    t2.start();
    synchronized (lock){
      Thread.sleep(1000L);
      lock.isGreen = true;
      System.out.println("Let`s go!");
      lock.notifyAll();
    }
    t1.join();
    t2.join();
    System.out.println("_exiting from main...");
  }
}

class Car implements Runnable {
  private final String name;
  private final LightSignal lock;

  public Car(String name, LightSignal lock) {
    this.name = name;
    this.lock = lock;
  }

  @Override
  public void run() {
    int distance = 100;
    synchronized (lock){
      try{
        while (!lock.isGreen){
          System.out.println(name + " waiting...");
          lock.wait();
        }
      }catch (InterruptedException e){
        e.printStackTrace();
      }
    }
    System.out.println(name + " started...");
    while (distance != 0){
      try{
        Thread.sleep((long) (100 * Math.random()));
      }catch (InterruptedException e){
        e.printStackTrace();
        break;
      }
      distance--;
      if (distance % 20 == 0 && distance != 0){
        System.out.println(name + " " + distance + " miles left");
      }
    }
    System.out.println(name + " finished race!!!");
    System.out.println("_exiting from thread of " + name + " move simulation...");
  }
}

class LightSignal {
  public boolean isGreen = false;
}
4

1 に答える 1

1

notifyAll() を呼び出すときは状態を変更する必要があり、waiting() しているときはループでその状態を確認する必要があります。これをしないと

  • notifyAll() は、後で待機を開始するスレッドではなく、待機中のスレッドにのみ通知します。
  • wait() は誤ってウェイクアップする可能性があります。

この場合、最も簡単な解決策は、気にしないことです。最大 100 ミリ秒のランダムな遅延を待機しているため、そのようなランダムなシステムの開始を同期しようとしても、大きな違いが生じる可能性は低くなります。

ループが終了すると、「レースは終了しました」と思いますが、ifこれには句は必要ありません。

于 2013-05-06T14:07:35.230 に答える