質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

Q&A

解決済

1回答

1122閲覧

synchronized, notyfiAllの適用について

namurunrun467

総合スコア1

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

0グッド

0クリップ

投稿2020/07/06 19:36

編集2020/07/07 03:01

2つのスレッドを交互に実行できるようにしたい

マルチスレッドを用いてXXとYYが交互に表示されるプログラムを作りたいです。
XXを表示するスレッドを実行

nをfalseとし、wait

YYを表示するスレッドを実行

notifyAllでXXを表示するスレッドを再開し、nをtrueとし、YYを表示するスレッドをwait

以降繰り返し
と考えたのですがうまく動きません。
初心者のため大変見苦しい書き方だとはおもいますがご教授おねがいします。

期待する出力結果
XX
YY
XX
YY

該当のソースコード

Java

1class ThreadXX2 extends Thread { 2 MessagePrint m = null; 3 public static boolean n = true; 4 5 public ThreadXX2(MessagePrint nm) { 6 super(); 7 m = nm; 8 } 9 10 public synchronized void s1(){ 11 while(true){ 12 while (n == true) { 13 try { 14 wait(); 15 } catch (InterruptedException e) { 16 } 17 } 18 19 m.message("XX"); 20 n=true; 21 notifyAll(); 22 } 23 } 24 25 public void run() { 26 s1(); 27 } 28} 29 30 31class ThreadYY2 extends Thread { 32 MessagePrint m = null; 33 34 public ThreadYY2(MessagePrint nm) { 35 super(); 36 m = nm; 37 } 38 public synchronized void s2(){ 39 while(true){ 40 while (ThreadXX2.n == false) { 41 try { 42 wait(); 43 } catch (InterruptedException e) { 44 } 45 } 46 m.message("YY"); 47 ThreadXX2.n=false; 48 notifyAll(); 49 } 50 } 51 52 public void run() { 53 s2(); 54 } 55} 56 57 58class MessagePrint { 59 public void message(String text) { 60 System.out.println(text); 61 } 62} 63 64public class ThreadEx2 { 65 public static void main(String[] args) { 66 final MessagePrint m = new MessagePrint(); 67 new ThreadXX2(m).start(); 68 new ThreadYY2(m).start(); 69 } 70} 71

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2020/07/07 02:42

「boolean n」を、2つのスレッド間の(言うなれば)同期用フラグにしたいのが主題でしょうか。
namurunrun467

2020/07/07 02:57

おっしゃる通りです。 XXの表示を行ったあと「boolean n」の値を変更し自身はwait,もう一方のスレッドにてYYを表示し再び「boolean n」の値を変更、(notyfiAllにて先のwaitしたスレッドを再開し、)このスレッドはwait...繰り返しというのが目標です。
guest

回答1

0

ベストアンサー

質問者さんのコードが意図通り動作しないのは、waitnofityAllでモニターしている(対象としている)オブジェクトがそれぞれ別のスレッドのthisであるからです。例えばThreadXX2s1メソッド内のwait();は、冗長に書くとthis.wait()です。また、notifyAll();に関してもthis.nofityAll()で、自スレッドの待機を解除できるのは自スレッドのみであり、これがThreadXX2ThreadYY2それぞれに言えているので相互に対話していることにならず、停止したままになっています。振り返って考えてみてください。質問者さんの元のコードではそれぞれのスレッドでwaitnofifyAllを実行していますが、コード上で関連しているようには見えないと思いませんか?

様々なやり方はあると思いますが、ある値がtrueであるときにThreadXX2が動き、またそのある値がfalseであるときにThreadYY2が動くようにする、と言うのであれば、そのある値を同期用に共有するオブジェクトにします。尚、質問者さんのオリジナルのコードではその共有値はpublic static boolean n;で扱っていますが、マルチスレッドでの運用では値の更新と読み取り時にガードが甘いものとなり、一貫性が保てなくなります。(今のコードではほとんど問題になりませんが)

そんなことを踏まえた上で修正してみたものが以下のコードです。自作のSignalクラスのインスタンスを共通に参照するオブジェクトとしてtrueのときはThreadXX2falseのときはThreadYY2が待機を解除して実行を続けるようになっています。synchronizedキーワードを指定している位置が変わっているのにも注意してみてみてください。

Java

1class Signal { 2 private boolean value; 3 4 public Signal(boolean initial) { 5 this.value = initial; 6 } 7 8 // 指定のboolean値になるまで待機 9 public synchronized void waitFor(boolean value) throws InterruptedException { 10 while (this.value != value) { 11 this.wait(); 12 } 13 } 14 15 // 指定のboolean値をセットしてnotifyAll(イベント発火) 16 public synchronized void setEvent(boolean value) { 17 this.value = value; 18 this.notifyAll(); 19 } 20} 21 22class ThreadXX2 extends Thread { 23 MessagePrint m = null; 24 Signal signal = null; 25 26 public ThreadXX2(MessagePrint nm, Signal signal) { 27 super(); 28 m = nm; 29 this.signal = signal; 30 } 31 32 public void s1() { 33 try { 34 while (true) { 35 System.out.println("ThreadXX2.s1(): while1"); 36 37 // trueになるまで待機 38 signal.waitFor(true); 39 m.message("XX"); 40 41 // ThreadYY2のスレッドの待機を解除すべく、falseにセット。 42 signal.setEvent(false); 43 44 Thread.sleep(500); 45 } 46 } catch (Exception e) { 47 System.out.println("ThreadXX2.s1() - Exception:" + e.getMessage()); 48 } 49 } 50 51 public void run() { 52 s1(); 53 } 54} 55 56class ThreadYY2 extends Thread { 57 MessagePrint m = null; 58 Signal signal = null; 59 60 public ThreadYY2(MessagePrint nm, Signal signal) { 61 super(); 62 m = nm; 63 this.signal = signal; 64 } 65 66 public void s2() { 67 try { 68 while (true) { 69 System.out.println("ThreadYY2.s2(): while1"); 70 71 // falseになるまで待機 72 signal.waitFor(false); 73 m.message("YY"); 74 75 // ThreadXX2のスレッドの待機を解除すべく、trueにセット。 76 signal.setEvent(true); 77 78 // 視認し易くする為500ミリ秒待機 79 Thread.sleep(500); 80 } 81 } catch (Exception e) { 82 System.out.println("ThreadYY2.s2() - Exception:" + e.getMessage()); 83 } 84 } 85 86 public void run() { 87 s2(); 88 } 89} 90 91class MessagePrint { 92 public void message(String text) { 93 System.out.println(text); 94 } 95} 96 97public class ThreadEx2 { 98 public static void main(String[] args) { 99 100 // 共有のシグナル(イベント)オブジェクトを生成 101 Signal signal = new Signal(true); 102 final MessagePrint m = new MessagePrint(); 103 new ThreadXX2(m, signal).start(); 104 new ThreadYY2(m, signal).start(); 105 } 106}

これを実行すると端末上において以下のような出力が得られます。Javaのバージョンは、OpenJDKの 1.8.0_252 です。

sh

1$ javac ThreadEx2.java 2$ java ThreadEx2 3ThreadXX2.s1(): while1 4XX 5ThreadYY2.s2(): while1 6YY 7ThreadXX2.s1(): while1 8XX 9ThreadYY2.s2(): while1 10YY 11ThreadXX2.s1(): while1 12XX 13ThreadYY2.s2(): while1 14YY 15ThreadXX2.s1(): while1 16XX 17ThreadYY2.s2(): while1 18YY 19ThreadXX2.s1(): while1 20XX 21ThreadYY2.s2(): while1 22YY 23ThreadXX2.s1(): while1 24XX 25ThreadYY2.s2(): while1 26YY 27...ずっと続く

例をもうひとつ挙げます。waitnotifyAll(含むnotify)のメソッドはその対象のオブジェクトが合致していればいいわけなので、上記のように共通のオブジェクトを使うのではなく、ThreadXX2ThreadYY2のそれぞれのインスタンスを直接指定することでも相互に待機、解除させることができます。コードの例としては分かりづらい気はするので、参考程度に読んでいただくのが良いかもしれません。これもsynchroizedキーワードの位置に注意してみてください。

Java

1class ThreadXX2 extends Thread { 2 MessagePrint m = null; 3 ThreadYY2 yy2 = null; 4 5 public ThreadXX2(MessagePrint nm) { 6 super(); 7 m = nm; 8 } 9 10 public void setThreadYY2(ThreadYY2 yy2) { 11 this.yy2 = yy2; 12 } 13 14 public void s1(){ 15 while(true){ 16 System.out.println("ThreadXX2.s1(): while1"); 17 m.message("XX"); 18 synchronized(yy2) { 19 yy2.notifyAll(); 20 } 21 22 try { 23 synchronized(this) { 24 wait(); 25 } 26 27 Thread.sleep(500); 28 } catch (Exception e) { 29 System.out.println("ThreadXX2.s1(): Exception " + e.getMessage()); 30 } 31 } 32 } 33 34 public void run() { 35 s1(); 36 } 37} 38 39class ThreadYY2 extends Thread { 40 MessagePrint m = null; 41 ThreadXX2 xx2 = null; 42 43 public ThreadYY2(MessagePrint nm) { 44 super(); 45 m = nm; 46 } 47 48 public void setThreadXX2(ThreadXX2 xx2) { 49 this.xx2 = xx2; 50 } 51 52 public void s2(){ 53 while(true){ 54 System.out.println("ThreadYY2.s2(): while1"); 55 m.message("YY"); 56 synchronized(xx2) { 57 xx2.notifyAll(); 58 } 59 60 try { 61 synchronized(this) { 62 wait(); 63 } 64 65 Thread.sleep(500); 66 } catch (Exception e) { 67 System.out.println("ThreadYY2.s2(): Exception " + e.getMessage()); 68 } 69 } 70 } 71 72 public void run() { 73 s2(); 74 } 75} 76 77class MessagePrint { 78 public void message(String text) { 79 System.out.println(text); 80 } 81} 82 83public class ThreadEx2 { 84 public static void main(String[] args) { 85 final MessagePrint m = new MessagePrint(); 86 ThreadXX2 xx2 = new ThreadXX2(m); 87 ThreadYY2 yy2 = new ThreadYY2(m); 88 89 xx2.setThreadYY2(yy2); 90 yy2.setThreadXX2(xx2); 91 92 xx2.start(); 93 yy2.start(); 94 95 /* 96 xx2.join(); 97 yy2.join(); 98 */ 99 } 100}

投稿2020/07/07 10:10

dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

namurunrun467

2020/07/08 03:26

回答ありがとうございます。 私はオブジェクト指向というものの理解が追い付いてなかったようです。回答者様のご指摘にはっときづかされました。今後参考にさせていただき、精進したいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問