7

次のプログラムがあります。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class SimpleWaitNotify implements Runnable {

final static Object obj = new Object();
static boolean value = true;

public synchronized void flag()  {
    System.out.println("Before Wait");
    try {
        obj.wait();
    } catch (InterruptedException e) {
        System.out.println("Thread interrupted");
    }
    System.out.println("After Being Notified");
}

public synchronized void unflag() {
    System.out.println("Before Notify All");
    obj.notifyAll();
    System.out.println("After Notify All Method Call");
}

public void run() {
    if (value) {
        flag();
    } else {
        unflag();
    }
}

public static void main(String[] args) throws InterruptedException {
    ExecutorService pool = Executors.newFixedThreadPool(4);
    SimpleWaitNotify sWait = new SimpleWaitNotify();
    pool.execute(sWait);
    SimpleWaitNotify.value = false;
    SimpleWaitNotify sNotify = new SimpleWaitNotify();
    pool.execute(sNotify);
    pool.shutdown();

}

}

obj を待機するException in thread "pool-1-thread-1" java.lang.IllegalMonitorStateException: current thread not ownerと、2 つのスレッドのそれぞれについて次の例外が発生します。

しかし、SimpleWaitNotify のモニターを使用すると、プログラムの実行が中断されます。つまり、現在の実行スレッドを一時停止し、実行者を一時停止すると思います。何が起こっているのかを理解するための助けをいただければ幸いです。

これは、理論とjavadocが単純に見える領域1であり、例があまりないため、概念的に大きなギャップがありました。

4

3 に答える 3

12

waitand notifyAllonを呼び出してobjいますが、同期していますthis(同期されたメソッドがあるため)。

待機または通知するには、最初にモニターを「所有」する必要があります。メソッドの同期を解除し、代わりに obj で同期します。

public void flag()  {
    System.out.println("Before Wait");
    synchronized (obj) {
        try {
            obj.wait();
        } catch (InterruptedException e) {
            System.out.println("Thread interrupted");
        }
    }
    System.out.println("After Being Notified");
}

public void unflag() {
    System.out.println("Before Notify All");
    synchronized (obj) {
        obj.notifyAll();
    }
    System.out.println("After Notify All Method Call");
}
于 2010-04-12T18:48:27.250 に答える
3

synchronizeon obj、または call waitand notifyonのいずれかthis。呼び出しスレッドは、これらのメソッドが呼び出される同じオブジェクトのモニターを保持する必要があります。

例えば、

synchronized void flag() {
  System.out.println("Before Wait");
  try {
    wait();
  } catch (InterruptedException e) {
    System.out.println("Thread interrupted");
  }
  System.out.println("After Being Notified");
}

この例では、ロックが保持されますthis(モディファイアsynchronizedがインスタンス メソッドで使用されると、インスタンスのモニターが取得されます)。したがって、wait()メソッドは暗黙のインスタンスで呼び出される場合がありますthis


2 つのスレッドを調整するには、同じロックを共有する必要があります。元のバージョンにはobj、ロックとして使用できる static がありましたが、synchronizedブロックでは使用されませんでした。より良い例を次に示します。

class SimpleWaitNotify implements Runnable {

  private final Object lock;
  private final boolean wait;

  SimpleWaitNotify(Object lock, boolean wait) {
    this.lock = lock;
    this.wait = wait;
  }

  public void flag()  {
    synchronized (lock) {
      System.out.println("Before Wait");
      try {
        lock.wait();
        System.out.println("After Being Notified");
      } catch (InterruptedException ex) {
        System.out.println("Thread interrupted");
      }
    }
  }

  public void unflag() {
    synchronized(lock) {
      System.out.println("Before Notify All");
      lock.notifyAll();
      System.out.println("After Notify All Method Call");
    }
  }

  public void run() {
    if (wait) {
      flag();
    } else {
      unflag();
    }
  }

  public static void main(String[] argv) throws Exception {
    ExecutorService pool = Executors.newFixedThreadPool(4);
    Object shared = new Object();
    SimpleWaitNotify sWait = new SimpleWaitNotify(shared, true);
    pool.execute(sWait);
    SimpleWaitNotify sNotify = new SimpleWaitNotify(shared, false);
    pool.execute(sNotify);
    pool.shutdown();
  }

}
于 2010-04-12T18:57:51.770 に答える
1

直言を入れるよりもpool.shutdown()、以下のようにしてみてください。

while (!service.isTerminated())
{
    service.shutdown();
}

したがって、すべてのスレッドの実行が完了するまで待機します。

于 2013-03-04T06:17:50.823 に答える