解決済み

notifyAll()の挙動について

  • 暇なときにでも
  • 質問No.9615030
  • 閲覧数62
  • ありがとう数2
  • 気になる数0
  • 回答数1
  • コメント数0

お礼率 66% (2/3)

こんにちは、マルチスレッドを勉強し始めた者です。
私の見立てが間違っていなければ、表題のとおり、notifyAllがどのように他のスレッドにwaitの解除を通知しているかを知りたいです。

事の始まりはsleep sortをマルチスレッドで実装しようと思ったことです。
sleep sortは表示までの時間がずれないことが重要だと考えましたので、すべてのスレッドが一斉に動いたほうが良いと思いました。
そこでネットで調べたところ、waitとnotifyAllを使うことでこれが実現できると考えまして、この二つを用いて実装を試みました。
以下がコードになります。

環境:Windows 7 64bit
IDE:Eclipse 4.5.2
JDK:1.8

【SleepSortSample.java】
package exp01;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class SleepSortSample {

public synchronized void print(int n){
try {
wait();
Thread.sleep(n*10);
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
System.out.print(n+",");
}

public synchronized void note(){
notifyAll();
}

public static void main(String...args) {
SleepSortSample sleepSortSample = new SleepSortSample();
List<Integer> list = IntStream.range(0, 30).boxed().collect(Collectors.toList());
Collections.shuffle(list);

list.stream().forEach(c -> System.out.print(c + ","));
System.out.println();

for (Integer integer : list) {
new Thread(()->sleepSortSample.print(integer.intValue())).start();
}

new Thread(sleepSortSample::note).start();
}

}
------------------------------------------

しかしながら、このコードだと以下のように全くソートが行われていません。

【出力例】
17,19,18,24,13,0,27,14,6,29,28,20,5,25,12,16,26,23,3,22,10,9,21,1,11,8,2,15,4,7,
7,4,15,2,8,11,1,21,9,10,22,3,23,26,16,12,25,5,6,20,28,14,29,13,27,0,17,18,24,19,

このことから察するにnotifyAllはすべてのスレッドに同時に告知をするものではないことと、この告知に意外と時間がかかる、と言う風に推察しました。
ですが、公式ドキュメントを読んでもそのことについての記述が無いため、この考えが正しいかどうかの確認が出来ませんでした。

どなたかご存知の方がいれば教えていただきたく思います。
それともし可能ならすべてのスレッドを同期させる良い方法も教えていただけると幸いです。
よろしくお願いします。

※OKWAVEより補足:「Webシステム開発」についての質問です。

質問者が選んだベストアンサー

  • 回答No.1

ベストアンサー率 28% (1353/4755)

Java カテゴリマスター
>このことから察するにnotifyAllはすべてのスレッドに同時に告知をするものではないことと、この告知に意外と時間がかかる、と言う風に推察しました。

synchronizedされていますから同時に動くことがないことに注意してください。
wait()は一時的にsynchronizedでのロック状態を一時的に解除し自スレッドが停止し他スレッドが動作できるようにします。
notifyAll()呼出しで他のスレッドに告知はされますが、wait()している他スレッドが再開できるのは、notifyAll()呼出しスレッドのsynchronizedでのロック状態解除後になります。
またwait()していた他スレッドはロックの再取得で奪い合いをしロックが取得できたスレッドが再開されロックを取得できなかったスレッドはロックの再取得のチャンスを待つことになります。
お礼コメント
mental_HELLth

お礼率 66% (2/3)

回答いただきましてありがとうございました!
理解しました!

つまりこの処理は並列処理にはなっていない、ということですね?
結局今回の例で行けば30個スレッドがwaitしているところにnotifyAllがされると、ロックを取得できたものから順々にスレッドが実行されていく、という処理がなされると理解しました。
ということはnotifyAllは同時に実行してほしい時に使えるものではないと言うことですね。

ともあれ非常にわかりやすい回答でした!
ありがとうございました。
投稿日時 - 2019-05-10 09:45:22
結果を報告する
このQ&Aにはまだコメントがありません。
あなたの思ったこと、知っていることをここにコメントしてみましょう。
AIエージェント「あい」

こんにちは。AIエージェントの「あい」です。
あなたの悩みに、OKWAVE 3,600万件のQ&Aを分析して最適な回答をご提案します。

その他の関連するQ&A、テーマをキーワードで探す

キーワードでQ&A、テーマを検索する

ピックアップ

ページ先頭へ