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

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

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

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

Q&A

解決済

2回答

2344閲覧

【Java】スレッドのデッドロックの原因について

kazu0630

総合スコア26

Java

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

0グッド

0クリップ

投稿2020/04/29 09:43

編集2020/04/29 12:18

いつもお世話になっております。

以下のコードで、デッドロックが発生してしまっているようなのですが、なぜデッドロックになっているのでしょうか。

showメソッドの排他制御が原因でデッドロックになっているということまでは分かっているのですが、排他制御についての理解が乏しく、なぜデッドロックになっているのかが分かっておりません。

以下問題集の内容抜粋

Java

1public class Test { 2 3 public static void main(String[] args) { 4 // TODO 自動生成されたメソッド・スタブ 5 6 CountThread c1 = new CountThread(); 7 CountThread c2 = new CountThread(); 8 c1.setCountThread(c2); 9 c2.setCountThread(c1); 10 c1.start(); 11 c2.start(); 12 } 13} 14 15class CountThread extends Thread { 16 CountThread c; 17 int i = 0; 18 19 public void setCountThread(CountThread c) { 20 this.c = c; 21 } 22 23 public synchronized void display(CountThread c) { 24 try { 25 Thread.sleep(10); 26 c.show(); 27 } catch (InterruptedException e) { 28 29 } 30 } 31 32 public synchronized void show() { 33 System.out.println(c.getName()); 34 } 35 36 public void run() { 37 display(c); 38 } 39 40} 41

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

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

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

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

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

dodox86

2020/04/29 10:07

そもそもですが、コードの意図が分かりません。c1.setCountThread(c2); と、c1のインスタンスにc2を預け、c2にc1を預けているのは何故でしょう。やりたいことが分からないです。synchronizedメソッドが思いっきり競合しているように見えます。何か、排他制御したいリソースをカウントしたい意図があるのでしょうか。c.getName()と、getNameインスタンスメソッドが見当たりませんが、コードの一部なのでしょうか。
退会済みユーザー

退会済みユーザー

2020/04/29 10:08

行番号はいれないでください。 マークダウン記法の意味がありません
kazu0630

2020/04/29 10:30 編集

dodox86さん 実はこれは私が書いたものではなく、問題集のコードです。 なので、私が意図して書いたソースコードではありません。 getNameメソッドについては、CountThread extends Threadとなっており、Threadクラスを継承しているため、ThreadクラスのgetNameメソッドを呼び出しているようです。 asahina1979さん 行番号は削除致しました。
dodox86

2020/04/29 10:32

> 実はこれは私が書いたものではなく、問題集のコードです。 なるほど、デッドロックするコードなので、その原因を探って直せ、と言う問題だということですか。
kazu0630

2020/04/29 10:34

コードをコンパイル、実行するとどういう結果になりますいか?という問題で、答えがデッドロックになるという解答になっております。 私の理解が乏しく、なぜそのようになっているのかが分からず、質問をさせていただいた次第です。
退会済みユーザー

退会済みユーザー

2020/04/29 12:15

問題集の問題ならその旨を書きましょう。
kazu0630

2020/04/29 12:18

asahina1979さん 追記致しました
guest

回答2

0

ベストアンサー

synchronizedメソッドは言わばそのスレッドのthisをロックオブジェクトとして動作します。※「synchronizedメソッドはそのスレッドのthisを使っている」相当の記述は公式では見当たらないので、単なるこの場での「例え」です。ご注意ください。
Synchronized Methods - ORACLE The Java Tutorials

ご提示のコードを例に、流れの説明を試みます。まず、c1.start();の実行によりc1のインスタンスのスレッドがrun()で始動し、c1のインスタンスでsynchronized display()を実行します。ここで、c1はロック状態になります。-- (1)

ほぼ同時にc2.start();の実行によりc2のインスタンスのスレッドがrun()で始動します。c2のインスタンスでsynchronized void display()を実行します。ここで、c2のスレッドもロック状態になります。-- (2)

c1によるsynchronized void display()の実行では、Thread.sleep(10)により10ミリ秒待機後にあらかじめプライベートフィールドにセットしたc2のインスタンスでc2.show()を実行しますが、このshow()synchronizedメソッドです。先に (2)にてc2はロック状態になったままであるので、実行がブロックされます。

同様に、c2によるsynchronized void display()の実行では、Thread.sleep(10)による10ミリ秒待機後、あらかじめプライベートフィールドにセットしたc1のインスタンスでc1.show()を実行します。先に (1)にてc1もロック状態になったままであるので、これも実行がブロックされます。c1c2もお互いに相手のブロック解除を待っている状態です。すなわちデッドロックです。

synchronizedメソッドではなく、メソッド内でsychronizedブロックに変更し、少々の確認用出力を加えると少しだけ分かりやすくなるかもしれません。

Java

1public class Test1c { 2 public static void main(String[] args) { 3 CountThread c1 = new CountThread(); 4 CountThread c2 = new CountThread(); 5 c1.setCountThread(c2); 6 c2.setCountThread(c1); 7 c1.start(); 8 c2.start(); 9 } 10} 11 12class CountThread extends Thread { 13 CountThread c; 14 int i = 0; 15 16 public void setCountThread(CountThread c) { 17 this.c = c; 18 } 19 20 //public synchronized void display(CountThread c) { 21 public void display(CountThread c) { 22 System.out.println("display: start." + c.getName()); 23 synchronized(this) { 24 try { 25 Thread.sleep(10); 26 System.out.println("display: try to call " + c.getName() + ".show()"); 27 c.show(); 28 } catch (InterruptedException e) { 29 30 } 31 } 32 } 33 34 // public synchronized void show() { 35 public void show() { 36 System.out.println("show: start." + c.getName()); 37 synchronized(this) { 38 System.out.println(c.getName()); 39 } 40 } 41 42 public void run() { 43 display(c); 44 } 45} 46

これを実行すると以下のような結果となります。show()内のsychronized(this)でブロックされているかたちを示しています。

sh

1$ javac Test1c.java 2$ java Test1c 3display: start.Thread-1 4display: start.Thread-0 5display: try to call Thread-1.show() 6show: start.Thread-0 7display: try to call Thread-0.show() 8show: start.Thread-1 9$ 10

投稿2020/04/29 17:09

dodox86

総合スコア9183

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

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

dodox86

2020/04/29 17:47

asahina1979さん、フォローありがとうございます。 synchronizedメソッドはスレッド(インスタンス)単位でブロックするということでthis相当のはずだと思っていたのもの、Javaの実装のソースコードレベルでそうなのかどうか、私自身で確信が持てませんでした。回答内容が一部でも裏打ちできました。感謝いたします。
kazu0630

2020/04/30 00:20

dodox86さん asahina1979さん ご回答いただき、ありがとうございます。 おかげさまで理解することができました。 丁寧にご回答いただき、ありがとうございました。 また機会がありましたら、宜しくお願い致します。
guest

0

オラクル認定資格教科書 Javaプログラマ Gold SE 8 スピードマスター問題集

これのことか。

こういうコードを記述するとデットロックになるから覚えろ系の問題かと
スレッド系はいろいろとアレだから。。。

●●●となる可能せいが高いか
(↑はずれとなる回答にもなる可能性が多少あるという問題もあるので)

投稿2020/04/29 12:21

編集2020/04/29 12:21
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問