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

このQ&Aに関連する最新のQ&A

A 回答 (2件)

evenThreadActionメソッドとoddThreadActionメソッドのc0及びc1が同じオブジェクトを参照するとデッドロック状態になるという認識でよろしいでしょうか?


ちなみに、スレッドのスィッチングは、Thread.sleep(2)の所でしか行われないと言う前提でしょうか?タスクの切替は、VMの仕様としては定義されていません。スィッチングのタイミングは、実装に依存(通常はOS任せ)です。よって、環境によっては、上記したsleepでしか切り替わりませんが、別の環境ではタイムスライス動くかもしれません。

waitとnotifyを何処で使えばデッドロックの回避が出来るかって事ですが、上記の状態にならなければ良いのですから、いずれかのスレッドが、c0を取得した時に、他のスレッドをwaitして、synchronizedを抜けたところで、notify(またはnotiflAll)すれば良さげですが...これだとマルチスレッドの意味無しですね。さらに他のスレッドに対してwaitしようと思ったら、他のスレッドの参照が出来る必要が出てきますね。なんか別の方法がありそうな気がしますが思いつきません。

あまり力になれなかったようで申し訳無い
    • good
    • 0

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

抜粋でかまいませんのでソースを載せて頂けませんか。

この回答への補足

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

補足日時:2001/07/28 00:38
    • good
    • 0
この回答へのお礼

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()を使った回避方法を知りたいです。よろしくお願い致します。

お礼日時:2001/07/28 16:31

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aと関連する良く見られている質問

Qjavaの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)みたいなら分かりいいんですが。

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(...続きを読む

Aベストアンサー

最初の回答にもあるように、anObject.wait()はanObject.notify()で目を覚ます。

標準的な使い方は:
public class SomeData{

 synchronized void get(){
  if(空){
   wait();
  }
  //データ取得処理
 }

 synchronized void put(){
  //データ収納処理
  notify();
 }
}
これで、複数のスレッドが同じSomeDataオブジェクトにアクセスする場合を調停する。

Qスレッドセーフなクラスのサブクラスは? synchronizedって継承先では?

1)メソッドにsynchronizedキーワードをつけた時、継承先のサブクラス側でもsynchronizedは生きているのでしょうか?

2)もし生きていると
サブクラス側で、synchronizedをとりけしたい場合
synchronizedをつけない形でオーバーライドして
中身の実装は super.メソッド名();
だけにするという方法しかないということでしょうか?

3)なお、
サブクラス側で、synchronizedキーワードを追加しながら
メソッドのオーバーライドができるということは
知っています。


4) (1)の答えが生きていない。とすれば・・。
スレッドセーフなクラスをがんばって作成しても、
サブクラス作成者がいちいち意識しなければ、
サブクラスはスレッドアンセーフになってしまう
ということでしょうか?
サブクラス作成者がたとえ、赤の他人でまったく、
コミュニケーションをとれない状況であろうとも、
そうならないようにするためのしかけを
作るためのテクニックはあるでしょうか?
なお、これはクラスをfinalしたくない場合の話です

以上です。

1)メソッドにsynchronizedキーワードをつけた時、継承先のサブクラス側でもsynchronizedは生きているのでしょうか?

2)もし生きていると
サブクラス側で、synchronizedをとりけしたい場合
synchronizedをつけない形でオーバーライドして
中身の実装は super.メソッド名();
だけにするという方法しかないということでしょうか?

3)なお、
サブクラス側で、synchronizedキーワードを追加しながら
メソッドのオーバーライドができるということは
知っています。


4) (1)の答えが生きていない。とす...続きを読む

Aベストアンサー

1)
生きています。というのも、

synchronized void method() {
........
}

というメソッドは、

void method() {
synchronized (this) {
........
}
}

というメソッドと同じように解釈されるからです。

2)
残念ながら、そうすることはできません。サブクラスのメソッドはシンクロナイズされていなくても、スーパークラスのメソッドはシンクロナイズされていますので、結局意味がありません。
synchronizedの宣言をサブクラスのメソッドで取り消すには、メソッドのコード全体を再び書く必要があります。

4)
(1)の答えが「生きている」でも危険性はありますよ。(2)の方法を使えばシンクロナイゼーションを解除できるわけですから。
ですから、いずれにしても、スーパークラス作成者あるいはサブクラス作成者がへまをやると、スレッドアンセーフになってしまいます。

もちろん、スーパークラス作成者が下のような「テクニック」を使えば、サブクラス作成者がへまをすることはなくなります。

class SampleClass {
 
 public final synchronized void method() {
  methodImpl();
 }
 
 protected void methodImpl() {
  ........
 }
 
}

外部からアクセスするメソッドと、オーバーライドされるメソッドを分けてしまえばよいわけです。

1)
生きています。というのも、

synchronized void method() {
........
}

というメソッドは、

void method() {
synchronized (this) {
........
}
}

というメソッドと同じように解釈されるからです。

2)
残念ながら、そうすることはできません。サブクラスのメソッドはシンクロナイズされていなくても、スーパークラスのメソッドはシンクロナイズされていますので、結局意味がありません。
synchronizedの宣言をサブクラスのメソッドで取り消すには、メソッドのコード全体を再び書く必要...続きを読む

Qwait()したスレッドが起こされるタイミング

以下のコードにおいて。

% 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 ThreadWaitTest 2
の場合はaと表示したまま止まりますが、
% java ThreadWaitTest 1
の場合はスレッドの終了に伴ってwait()が切れ、bまで表示します。
私の望む動作は前者です。

後者の場合、これはつまりスレッドをwaitした際の待機プールがスレッドオブジェクトの場合、そのスレッドの実行が終了すると待機プールにある待機スレッドを自動でnotify()してしまうことを意味していると思うのですが、この解釈はあっていますか?

Java のAPIドキュメントに

「別のス...続きを読む

Aベストアンサー

自信なし。
---

"spruious wakeup"みたいですが・・・。
("spurious wakeup"については、
「1.5以降のjavadocのObject#wait(long)の項」、
または
「Effective Java 項50」
などに簡単に記されている)

(今のところ)仕様とはされてないが、
現実には認知されている現象、というところだと思います。
---

"spurious wakeup"については、よく知らないので、
ネットで検索したり、
sunの「Bug Database」などで検索してみてください。
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4777391

Qwait中に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の初心者です。
どうしてもわからないことがあります。
例えば、以下のコードで、
class Foo
{
public synchronized void foo()
{
while(条件)
{
try
{
this.wait();
}
catch(InterruptedException ex)
   {
    処理
   }
}
}
}
wait中であったスレッドは、他のスレッドによって
interrupt()メソッドを実行されたときは、Fooの
ロックを取得してからcatch節を実行すると思うのですが、もし、以下のコード...続きを読む

Aベストアンサー

当然 Foo のインスタンス (Foo クラスじゃないよ!) のロックを取得してから例外がスローされます。
そもそもロックの取得も例外のスローも wait() メソッドの中で行われることなのだから、catch の有無によって動作が変わることなどありえません。wait() メソッドの中から呼び出し元 (つまり foo() メソッド) のコードがどうなっているかなんて知る由もありませんからね。

念のため foo() メソッドの全体の動作を書いておきます。
foo() メソッドがどこからか呼ばれる。

Foo のインスタンスのロックを取得

wait() メソッドが呼ばれる

(wait() メソッドの中で) Foo のインスタンスのロックを解除して、待機状態に入る

その後ほかのスレッドから interrupt されると、
(wait() メソッドの中で) Foo のインスタンスのロックを再取得して、InterruptedException をスローする

wait() メソッドから foo() メソッドに戻る

例外は foo() の中ではキャッチされない

Foo のインスタンスのロックを解除して、foo() メソッドを抜ける

InterruptedException は foo() の呼び出し元に伝播する

当然 Foo のインスタンス (Foo クラスじゃないよ!) のロックを取得してから例外がスローされます。
そもそもロックの取得も例外のスローも wait() メソッドの中で行われることなのだから、catch の有無によって動作が変わることなどありえません。wait() メソッドの中から呼び出し元 (つまり foo() メソッド) のコードがどうなっているかなんて知る由もありませんからね。

念のため foo() メソッドの全体の動作を書いておきます。
foo() メソッドがどこからか呼ばれる。

Foo のインスタンスのロックを取...続きを読む

Qスレッドの待機と再開

お世話になります。

マルチスレッドのプログラムで悩んでいます。

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() を呼び出すものとします。
そして、それぞれのスレッドは、お互いのインスタンスを知りません。(説明しづらいので、補足要求があれば、ソースで示します。)

よろしくお願いいたします。

お世話になります。

マルチスレッドのプログラムで悩んでいます。

public class ThreadLocker {
 private static boolean isLocked = false;
 
 public static void lock() {
  isLocked = true;
  while(isLocked) { ; }
 }
 
 public static void unlock() {
  isLocked = false;
 }
}

まず、このようなクラスを定義しました。そして複数のスレッドが ThreadLocker.lock(); を呼び出して、処理の進行をストップしている状態があるとします。この状態に対して、とある別のスレ...続きを読む

Aベストアンサー

参考URLの記事などを一通りお読みになった上で
わからない点を再度ご質問されるのがよろしいかと
思われます。

wait()は対象のオブジェクトに対して呼び出すので、
どこで呼んでもも構いませんが、対象のオブジェクトの
ロックをsynchronizedなどで獲得しておく必要が
あります。

参考URL:http://www.javaworld.jp/technology_and_programming/-/10941-1.html


このカテゴリの人気Q&Aランキング

おすすめ情報