• 締切済み

デッドロック回避のためのwait() notify()

学生です。最近javaの勉強をはじめました。 synchronized statementでデットロック回避のためにwait() notify()の使い方がよくわかりません。本にはwait()はスレッドがsynchronizedで獲得してあるロックを解放し、待機状態に入るとのことを書いてありましたが、なぜ、wait()をwhileループでまわすのでしょうか? それと、notifyは待機状態のスレッドに対して通知し、通知されたスレッドは待機状態から実行状態に移るとのことですが、whileループで再びwait()を実行し永遠に抜け出せないと思うのですがどうなんでしょうか? お手数ですが、詳しい方がいらしたら教えていただけないでしょうかお願いします。

  • kanep
  • お礼率50% (8/16)
  • Java
  • 回答数2
  • ありがとう数4

みんなの回答

  • akr
  • ベストアンサー率18% (32/173)
回答No.2

evenThreadActionメソッドとoddThreadActionメソッドのc0及びc1が同じオブジェクトを参照するとデッドロック状態になるという認識でよろしいでしょうか? ちなみに、スレッドのスィッチングは、Thread.sleep(2)の所でしか行われないと言う前提でしょうか?タスクの切替は、VMの仕様としては定義されていません。スィッチングのタイミングは、実装に依存(通常はOS任せ)です。よって、環境によっては、上記したsleepでしか切り替わりませんが、別の環境ではタイムスライス動くかもしれません。 waitとnotifyを何処で使えばデッドロックの回避が出来るかって事ですが、上記の状態にならなければ良いのですから、いずれかのスレッドが、c0を取得した時に、他のスレッドをwaitして、synchronizedを抜けたところで、notify(またはnotiflAll)すれば良さげですが...これだとマルチスレッドの意味無しですね。さらに他のスレッドに対してwaitしようと思ったら、他のスレッドの参照が出来る必要が出てきますね。なんか別の方法がありそうな気がしますが思いつきません。 あまり力になれなかったようで申し訳無い

  • akr
  • ベストアンサー率18% (32/173)
回答No.1

synchronizedでデッドロック回避と言っても何に対するデッドロックなんでしょか?文面を見る限り、何かソースを見ての疑問のように見うけられますが、そのソースが無いので、なんとも言えません。抜粋でかまいませんのでソースを載せて頂けませんか。

kanep
質問者

お礼

for(int i = 0 ; i < threadNumber ; i++) new BubbleSort(i, array, mc, latch).start() ; //////////////////// class BubbleSort extends Thread { private int number ; private Array array ; private MyCanvas mc ; private Latch latch ; BubbleSort(int n, Array a, MyCanvas m, Latch l) { number = n ; array = a ; mc = m ; latch = l ; } public void run() { try{ latch.acquire() ; if(number % 2 == 0) evenThreadAction() ; else oddThreadAction() ; System.out.println("****** Completed Thread No." + number) ; } catch(InterruptedException e){ } } private void evenThreadAction() { boolean complete = false ; while(!complete){ boolean changed = false ; for(int i = 0 ; i < array.getSize() - 1 ; i++){ Cell c0 = array.getCell(i) ; synchronized(c0){ Cell c1 = array.getCell(i + 1) ; synchronized(c1){ if(c0.getValue() > c1.getValue()){ c0.swapValue(c1) ; changed = true ; mc.repaint() ; try{Thread.sleep(2);}catch(InterruptedException e){} } } } } if(!changed) complete = true ; } } private void oddThreadAction() { boolean complete = false ; while(!complete){ boolean changed = false ; for(int i = array.getSize() - 1 ; i > 0 ; i--){ Cell c0 = array.getCell(i-1) ; synchronized(c0){ Cell c1 = array.getCell(i) ; synchronized(c1){ if(c0.getValue() > c1.getValue()){ c0.swapValue(c1) ; changed = true ; mc.repaint() ; try{Thread.sleep(2);}catch(InterruptedException e){} } } } } if(!changed) complete = true ; } } } 上のソースはプログラムのスレッドの処理の部分です。 プログラムの内容はバブルソートアルゴリズムを複数のスレッドを使って行った場合、生成順が奇数のスレッドと偶数のスレッドでアクションが逆なので処理を繰り返していくうちに典型的なデッドロックの状態になるということです。アルゴリズムを変えればデッドロックは回避できますが、そうではなくwait() notify()を使った回避方法を知りたいです。よろしくお願い致します。

kanep
質問者

補足

わざわざありがとうございます。 実はこれは授業の課題なのですが、ソースは研究室のPCにあり、 今、家に帰ってしまったため、載せることができません。 明日になってしまいますが、ソースを載せますのでお手数ですがよろしくお願い致します。

関連するQ&A

  • javaのwaitしてるスレッドをnotifyで起こすことが出来ない

    JDK1.5 WindowsXPです。 現在マルチスレッドを試しています。 A、B、C三つのスレッドがあります。 AはBというスレッドを作るメインスレッドです。 Bは、waitするスレッドです。 public final void run(){  while (true){   try {    //notifyが来るまで待機    waitForNotify();    //実際の処理    act();    //スレッド停止させるための割り込み例外   } catch (InterruptedException e) {    Thread.currentThread().interrupt();    e.printStackTrace();   }   //割り込み受信の場合強制終了する   if (Thread.currentThread().isInterrupted()) {    break;   }  } } こんな感じです。 そしてCのスレッドがnotify()を実行します。 しかしnotify()を実行してもスレッドは起きません。 Bに、 public synchronized void notifyM() throws InterruptedException{   wait(); } のようなメソッドを追加して、スレッドのインスタンスメソッドとして実行しても起きません。 notify()がJavaDOCなどを読んでも意味不明なため、 どのような使い方なら動くのか見当がつきませんので質問しました。 notify(スレッドB)みたいなら分かりいいんですが。

    • ベストアンサー
    • Java
  • wait()したスレッドが起こされるタイミング

    以下のコードにおいて。 % java ThreadWaitTest 2 の場合はaと表示したまま止まりますが、 % java ThreadWaitTest 1 の場合はスレッドの終了に伴ってwait()が切れ、bまで表示します。 私の望む動作は前者です。 後者の場合、これはつまりスレッドをwaitした際の待機プールがスレッドオブジェクトの場合、そのスレッドの実行が終了すると待機プールにある待機スレッドを自動でnotify()してしまうことを意味していると思うのですが、この解釈はあっていますか? Java のAPIドキュメントに 「別のスレッドが notify メソッドまたは notifyAll メソッドを呼び出してこのオブジェクトのモニター上で待機するスレッドに通知を出すまで待機します」 とあるように、ユーザが明確的にnotifyしないと起こらないと思いこんでいました。 なぜこういう仕様になっているのでしょうか? また、この仕様について詳しく書いてあるサイトやドキュメントなどありませんでしょうか? public class ThreadWaitTest extends Thread {  public Object mutex = new Object();    public static void main(String[] args) {   try {    ThreadWaitTest test = new ThreadWaitTest();    test.start();    System.out.println("a");    switch (new Integer(args[0])) {    case 1:     synchronized(test) {      test.wait();     }     break;    case 2:     synchronized(test.mutex) {       test.mutex.wait();     }     break;    }    System.out.println("b");   } catch (InterruptedException ie) {    ie.printStackTrace();   }  }  public void run() {   try {    Thread.sleep(5000);   } catch (InterruptedException ie){    ie.printStackTrace();}   } }

    • ベストアンサー
    • Java
  • wait中にinterruptを呼ばれたスレッドの振る舞いについて

    はじめまして。javaの初心者です。 どうしてもわからないことがあります。 例えば、以下のコードで、 class Foo { public synchronized void foo() { while(条件) { try { this.wait(); } catch(InterruptedException ex)    {     処理    } } } } wait中であったスレッドは、他のスレッドによって interrupt()メソッドを実行されたときは、Fooの ロックを取得してからcatch節を実行すると思うのですが、もし、以下のコードの場合は、 class Foo { public synchronized void foo() throws InterruptedException { while(条件) { this.wait(); } } } wait中であったスレッドは、他のスレッドによって interrupt()を実行されたときにすぐにInterrupted Exceptionをスローするのか、それとも Fooクラスのロックを取得してからInterruptedExceptionをスローするのかどちらなのか がわかりません。どうか教えてください。よろしく お願いします。

    • ベストアンサー
    • Java
  • 交互にスレッド実行 (どうしてちゃんと動いてる?)

    http://oshiete1.goo.ne.jp/qa2968378.html で質問した者です。 2つのスレッドで1と2を交互に実行する以下のプログラム。 final Object obj1 = new Object(); //スレッド間通信用のobject final Object obj2 = new Object(); //スレッド間通信用のobject2 Thread t1 = new Thread() {  public void run() {   try {    while(true) {     System.out.print("1");     synchronized (obj1) {      synchronized (obj2) {       obj2.notify();//相手をnotifyして      }      obj1.wait();//自分はwait     }    }   } catech (Exception e){} }; Thread t2 = new Thread() {  public void run() {   try {    while(true) {     System.out.print("2");     synchronized (obj2) {      synchronized (obj1) {       obj1.notify();      }      obj2.wait();     }    }   } catch (Exception e){}  } }; Thread t1 = new Test1(); Thread t2 = new Test2(); t1.start(); while(t1.getState() != Thread.State.WAITING); t2.start(); が思ったように動いてはいるものの、なぜ正常に動いているかがわかりません。 t1が wait() したときはobj1のロックをもっていて、t2の synchronized (obj1){obj1.notify()} ブロックに入れず待機するはずだと思うのですが。 なぜちゃんと動いているのでしょう?

    • ベストアンサー
    • Java
  • スレッド1とスレッド2を交互に実行するには?

    スレッド1→スレッド2→スレッド1・・・と同期を取り合いながら交互にスレッドを動かしたいのですが、Thread.getState()を用いないで実現するよい方法はないでしょうか? どうしてもデッドロックが発生しうる方法しか思いつかず困っています。 例えば以下のプログラムで1212と交互に表示させたい場合です。 以下のプログラムは当然デッドロックになりますが、やりたいことを伝えるために載せておきます。 Object obj; //スレッド間通信用のobject class Test1 extends Thread {  public void run() {   while(true) {    System.out.print("1");    synchronized (obj) {     obj.notify();//相手をnotifyして     obj.wait();//自分はwait    }   }  } } class Test2 extends Thread {  public void run() {   while(true) {    System.out.print("2");    synchronized (obj) {     obj.notify();     obj.wait();    }   }  } } new Test1().start(); new Test2().start();

    • ベストアンサー
    • Java
  • pthread_cond_wait での mutex

    以下の様なサンプルプログラム(一部省略)があります。 bossスレッドが1秒ごとにworkerスレッドを起こして、workerスレッドは処理後、再び眠ります。 worker () { while (...) { * pthread_mutex_lock(&g_lock); pthread_cond_wait(&g_signal, &g_lock); * pthread_mutex_unlock(&g_lock); : } } boss() { while (...) { wait( 1 ); * pthread_mutex_lock(&g_lock); pthread_cond_signal(&g_signal) * pthread_mutex_unlock(&g_lock); } } waitで待機し、signalで起こされるのはわかるのですが、 mutexでロックしている意味がわかりません。 mutexが不必要な処理の場合、*部分はいらないのでしょうか?

  • スレッドの待機と再開

    お世話になります。 マルチスレッドのプログラムで悩んでいます。 public class ThreadLocker {  private static boolean isLocked = false;    public static void lock() {   isLocked = true;   while(isLocked) { ; }  }    public static void unlock() {   isLocked = false;  } } まず、このようなクラスを定義しました。そして複数のスレッドが ThreadLocker.lock(); を呼び出して、処理の進行をストップしている状態があるとします。この状態に対して、とある別のスレッドが ThreadLocker.unlock(); を呼び出すと、それまで無限ループしていたスレッドが解放されて処理を始める、という感じです。 この方法を試してみましたが、無限ループで何も処理をしていないとは言え、リソースを食いまくっているようで、マシンが重くなってしまいました。 そこで、スレッドの待機・再開を行う事ができる wait / notify(All?) メソッドを使用すれば良いのではないかと考えたのですが、具体的な方法が分からず、質問させていただきました。 具体的に、どのインスタンスの wait 及び notify(All?) を呼び出せば良いのかが分かりません。 APIリファレンスの「現在のスレッドはこのオブジェクトのモニターのオーナでなければなりません。」の意味もよく分かりません。 ちなみに、待機しているスレッドは複数あり、class Lock の method execute 中で ThreadLocker.lock() しているとします。 また、再開を促すスレッドは1つで、class Unlock の method execute 中で ThreadLocker.unlock() を呼び出すものとします。 そして、それぞれのスレッドは、お互いのインスタンスを知りません。(説明しづらいので、補足要求があれば、ソースで示します。) よろしくお願いいたします。

    • ベストアンサー
    • Java
  • スレッド

    問題集を読んでいて、どうしても意味がわからなかった部分があります。五択になっていて、私は 「notify()実行の条件は、呼び出し元のスレッドが待機状態にあるスレッドのロックフラグを取得していることである」 を選んだんですが、これは間違いでした。 解説には待機スレッドのロックフラグは必要ではない、とあるのですが、では逆に言うとなんの(何処の)ロックフラグが必要になるのでしょうか? ご存知の方がいらっしゃいましたら、教えて下さい。 宜しくお願い致します。

    • ベストアンサー
    • Java
  • ロックの取得とwaitメソッド

    インスタンスに対してwait()メソッドを実行するには、そのインスタンスのロックを取得していなくてはならないと思っています。 method2()がエラーになるのと、method3が正常に動作するのは、 インスタンスに対するロックの有無で理解できます。 ただ、下記のソースでmethod()がエラーとならない動作が理解でき ませんでした。 このメソッドだと、メソッド単位ではロックがかかっていますが、 synchronizedでないメソッドが存在すれば別スレッドからアクセスでき るので、インスタンスに対するロックを取得しているわけではないと思 います。 私の理解が間違っているのでしょうか。 class MyClass { String str = new String("a"); public synchronized void method(){ try{ wait(); } catch (Exception e) { e.printStackTrace(); } } public void method2(){ synchronized (str) { try{ wait(); }catch(Exception e){ e.printStackTrace(); } } } public void method3(){ synchronized (this) { try{ wait(); }catch(Exception e){ e.printStackTrace(); } } } } class UseMyThread1 { public static void main(String args[]) { MyClass mc1 = new MyClass(); MyClass mc2 = new MyClass(); MyClass mc3 = new MyClass(); //mc1.method();//ここはエラーにならない System.out.println("*********"); //mc2.method2(); //ここはエラーになる System.out.println("*********"); //mc3.method3();//ここはエラーにならない } }

    • ベストアンサー
    • Java
  • メソッドの処理の同期化

    いつもお世話になっています。 メソッド処理の同期化についてなのですが、 いろいろ調べてみたのですが、いまいちうまく実行できません。 ソースを考えてみたのですが、どこがどう悪いのかご指摘お願いできますでしょうか? 以下のクラスがある場合で public void Add(){ synchronized(this){ System.out.println("待機しています!"); //おそらくここら辺にwait()/notify()処理が来るきがする //同期中に行わない処理をここに記載する? } System.out.println("Addメソッド実行しました"): } public void Change(){ synchronized(this) { //おそらくここら辺にwait()/notify()処理が来るきがする //同期中に行わない処理をここに記載する? //一時停止 処理時間をずらすためループを使用 try { for(int a=0;a<3;a++){ System.out.println("a="+a); Thread.sleep(10000); } }catch (InterruptedException e) { } System.out.println("Changeメソッド完了です"); } } このとき、Add対Change/Add対Addといった形で同期化処理をしたいのですが、どうしてもうまくできません。 仮にThreadを使用して実行してみようとしたのですが、 順番に実行されてしまいます。 したいのが、 1.Addメソッド実行 2・Addメソッド実行 この場合、現状だと a=0 a=0 a=1 a=1 a=2 a=2  と表示されてしまうので、 a=0 a=1 a=2 a=0 a=1 a=2  と表示することはできるのでしょうか? 原因として、wait()/notify()が記載されていないことが影響していると思うのですが。 宜しくお願いします。

専門家に質問してみよう