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

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

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

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Q&A

解決済

3回答

1235閲覧

デッドロックについて java

k.fujisawa

総合スコア39

Java

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

0グッド

1クリップ

投稿2024/05/25 17:40

編集2024/05/30 09:58

以下のソースにて、デッドロックは発生しますか?

※複数回、実行していますが、未だ、デッドロックは発生しておりません。

※標題:徹底攻略Java SE 11 Gold問題集[1Z0-816]対応
初版第一刷
著者:志賀 澄人
発行所:株式会社インプレス
引用頁:550

イメージ説明

java

1public class Main { 2 public static void main(String[] args) { 3 Test t1 = new Test(); 4 Test t2 = new Test(); 5 6 Sample s1 = new Sample(); 7 Sample s2 = new Sample(); 8 9 new Thread(() -> { 10 t1.execute(s1, s2); 11 }).start(); 12 13 new Thread(() -> { 14 t2.execute(s1, s2); 15 }).start(); 16 } 17} 18 19class Test { 20 public synchronized void execute(Sample... samples) { 21 for (int i = 0; i < 10; i++) { 22 while (!samples[0].hello(this)) { 23 } 24 while (!samples[1].hello(this)) { 25 } 26 samples[1].bye(); 27 samples[0].bye(); 28 } 29 } 30} 31 32class Sample { 33 public Test test; 34 35 public synchronized boolean hello(Test test) { 36 if (this.test == null) { 37 this.test = test; 38 return true; 39 } 40 return false; 41 } 42 43 public synchronized void bye() { 44 this.test = null; 45 } 46}

引用頁:595

解答

一方のスレッドが1つ目のインスタンスを使っているとき、もう一方のスレッドが2つ目のインスタンスを使っており、それぞれがもう1つのインスタンスを使おうとしたときに、synchronizedによってデッドロックが発生してしまう可能性があります。

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

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

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

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

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

y_waiwai

2024/05/25 22:46

実際に動かしてみたらどうなるんでしょうか。
k.fujisawa

2024/05/25 23:11

複数回、実行したところ、デッドロックは発生しておりません。
y_waiwai

2024/05/25 23:18

ならそこら辺も質問文に追記しましょう。 今の質問文では丸投げにしかなりません
k.fujisawa

2024/05/26 00:35 編集

追記しました。ありがとうございます。
jimbe

2024/05/26 05:52 編集

どこにも「一方をロックしたままもう一方のロックを求める」部分が無いように見えるんですが、どこでデッドロックが発生すると思われているのでしょうか。
k.fujisawa

2024/05/26 07:23 編集

私自身、デッドロックは発生しないと考えております。掲題のソースは参考書からの引用であり、このソースでデッドロックが発生するとの記載がありました。
ikedas

2024/05/26 06:42

書籍からの引用であれば引用元を明記してください。明記する内容は著者名、標題、出版社名、引用したページのページ番号です。 なお、このコメント欄に書くのではありません。質問文を編集して書いてください。
k.fujisawa

2024/05/26 07:26

無断での複製、複写が禁じられていたので、掲題のソースを削除しようかと思います。 書籍情報も明記せず、質問をクローズしようかと思います。
ikedas

2024/05/26 07:39

> 無断での複製、複写が禁じられていたので、掲題のソースを削除しようかと思います。 引用は無断でできます。そのように著作権法に決めてあります。 質問削除をしないでください。
k.fujisawa

2024/05/26 07:40

なに!ありがとうございます。ぱくられるかと思いました。
ikedas

2024/05/26 07:46 編集

著作権法 > 第三十二条 公表された著作物は、引用して利用することができる。この場合において、その引用は、公正な慣行に合致するものであり、かつ、報道、批評、研究その他の引用の目的上正当な範囲内で行なわれるものでなければならない。 この場合の「公正な慣行」の一部として、引用元を正確に示すことが必要です。また、写し間違いができるだけ起きないように注意することも必要です。 なお、クラス名MainをAppに書き換えているようです。しかし、著者に無断で意図的に内容を書き換えることは著作者の「同一性保持権」(同法第二十条) を侵すおそれがあります。そういう点でも、引用は正確にお願いします。
ikedas

2024/05/26 08:01

私が立ち読みしたのと違うみたいですね。私が見たのは2023年11月1日第1版第5刷ですが、そちらが見ているのは第何刷ですか (本の一番最後のページに書いてあります)。 こちら https://book.impress.co.jp/books/1121101020 の正誤表にも載ってないようですね。 確証を得たければ、問い合わせフォームから問い合わせてみるのがいいと思います。
k.fujisawa

2024/05/26 08:53

本の1番最後のページには、「2021年9月21日 初版発行」と書かれておりますが。。。
k.fujisawa

2024/05/26 09:58

正誤表の「第2刷にて修正」と同じ誤りがあるため、第1刷?かと思います。
ikedas

2024/05/26 10:16

発行日付からみて初版第1刷ですね (私の見たのはその下に「 2023年11月1日 第1版第5刷発行」と書いてありました)。紙の書籍にしてはかなり頻繁に訂正をしてくれているようです。 初版第5刷は私は立ち読みしただけなので、見間違いもあるかもしれません。一方で、出版社が正誤表に載せていない訂正もあるのかもしれません。機会があったら書店で確かめてみてください。
k.fujisawa

2024/05/26 10:28

いろいろ教えていただき、ありがとうございます。正誤表を自分で確認できるようになりました。ありがとうございます。
jimbe

2024/06/03 15:29 編集

この本(の第2刷)の "間違い" について問い合わせしすぎて(?) 何かもうアンチになっちゃったみたいな記事がありました。 [Java Goldの黒本に対する批判] https://qiita.com/kaganatsu/items/049d06131d0ab69f009b けど、本件の部分については記述は無さそうです。(長いので後半は流し読みになってしまいました。) 書店にて第6刷を見ましたが該当問題も解答も変わっていませんでした。
k.fujisawa

2024/06/03 15:08

ありがとうございます!
guest

回答3

0

ベストアンサー

05/30 01:15追記

解決済みになっていますが、本当に正しいのかちょっと疑わしいので情報をまとめておきます。

長々と書いてしまいましたが質問者さんや同様の疑問を抱いてこの質問に辿り着いた方の一助になれば…ということで。

勝手な用語の定義

  • 広義のデッドロック
    複数の共有リソースを用いた処理において、複数のスレッド/プロセスが互いにリソースの解放待ちでそれ以上処理を進められなくなる状態
  • 狭義のデッドロック
    広義のデッドロックのうち、言語特有のロック機能を用いているもの(Javaのsynchronized等)

※この記事のために私が勝手に導入した用語です

「徹底攻略Java SE 11 Gold問題集」の修正内容

以降、「徹底攻略Java SE 11 Gold問題集」のことを単に「書籍」と呼びます。

  • 誤植修正前 (2021年9月21日 初版)
    • コード
      t1.execute(s1, s2);
      t2.execute(s1, s2);
    • 書籍の回答
      『デッドロックの可能性がある』
  • 誤植修正後 (2023年11月1日 第1版第5刷)
    • コード
      t1.execute(s1, s2);
      t2.execute(s2, s1);
    • 書籍の回答
      『デッドロックの可能性がある』

※誤植修正前のコードでは、実際にはデッドロックは発生しない

(質問者さんの引用&ikedasさんの書き込みより)

私の考える正しい解釈

一般的にデッドロックと言えば、広義のデッドロックを指すと私は考えています。

書籍でも同じく広義のデッドロックの意図で問題を作成したところ
誤植修正前にはコードの一部に誤りがあり、誤植修正後はコードと回答が一致するようになった…と考えています。

現時点でベストアンサーになっているjimbeさんの回答は、『狭義のデッドロックが起こらない』という趣旨なのか、
あくまで書籍の誤植修正前のコードについて論じているだけなのか判断が付きませんでした。

ただ、質問者さんは狭義のデッドロックについてだと解釈されているように思われます。
質問者さんが私の回答へのコメントで「デッドロックではなく、ただの無限ループ」と発言されていますが
実際は「狭義のデッドロックではないが、無限ループによる広義のデッドロック」という解釈が正しいと私は考えています。

一般的な定義ではなく、Java Gold試験におけるデッドロックの定義について

仮にJava Gold試験でのデッドロックの定義が狭義のデッドロックのことであるなら(例えばoracleの試験要綱等に記載があれば)
少なくとも試験においては一般的な(と私が考えている)定義ではなく、そちらに合わせて回答すべきです……が
そうすると書籍の方が誤った定義の出題をしていることになってしまいます。

試験のための知識だとしても、出題側がどういう意図なのか試験要綱や試験のための参考書の記述を確認してみてほしいです。

コードの書き方の問題

今回のコードはあまり普通の書き方をされていないので、それも混乱の原因になったとは思います。
解放待ちにウェイトも付けず何も処理を入れないならば素直にsynchronizedで待てばよくて、空の無限ループは用いるべきではありません。
また質問者さんが引用されているコードが一字一句そのままであるなら、実用コードであれば存在するはずの共有リソースを用いた処理について何も(省略の旨のコメントすら)書かれておらず
実際にコードを走らせて検証してもおそらくタイミング問題でデッドロックが再現しにくいのではないかと思われます。

資格試験で理解度を問うためにわざと分かりにくいコードの書き方をしているのかな?くらいの解釈だったので特に言及しませでしたが……
実際のデッドロックを論じる検証コードであれば、普通は実処理を模したsleepを入れたり、確認のための標準出力処理を入れたりします。
デッドロックの再現はタイミング問題なので「何度実行してみても再現しない」というのもよくあり、そこでこのsleepを増減させたり標準出力をなくしたりと色々工夫して検証することになります。

そういう事情もあるので、たまたま実行した時にデッドロックが発生しないから「コードに問題がない」と短絡的に考えるのではなく、「デッドロックが発生しうる構造かどうか」を考える力が必要となります。
今回の誤植修正後のようなコードを対象にする場合などは、狭義のデッドロックか否かを論じても実用的にはとくに意味がないと考えています。
(「デッドロックは発生しないがリソースの取り合いで処理が終了しない構造なので修正しなければならない」みたいな意味の分からない会話が生まれてしまいます)

件のコードでの広義のデッドロック発生について

誤植修正前の説明は05/26時点で書いたので
誤植修正後のコードについて

t1.execute(s1, s2);
t2.execute(s2, s1);
の場合の実行イメージについて
以下のようなタイミングで実行されると広義のデッドロックが再現できます。

  1. 初期状態 s1.test == null かつ s2.test == null
  2. 2スレッドで(ほぼ)同時に最初の while 文を実行
    1. t1 のスレッドでループ判定の !samples[0].hello(this) を実行
      つまり s1.hello(t1) がtrueを返し、whileループ終了
    2. t2 のスレッドでループ判定の !samples[0].hello(this) を実行
      つまり s2.hello(t2) がtrueを返し、whileループ終了
    ※この時点で何も競合していない
  3. 状態 s1.test == t1 かつ s2.test == t2
  4. 2スレッドでほぼ同時に次の while 文を実行
    1. t1 のスレッドでループ判定の !samples[1].hello(this) を実行
      つまり s2.hello(t1) がfalseを返し、whileループ継続 (無限に終わらない)
    2. t2 のスレッドでループ判定の !samples[1].hello(this) を実行
      つまり s2.hello(t2) がfalseを返し、whileループ継続 (無限に終わらない)
    ※メソッド呼び出しのsynchronizedで止まるわけではないが、t1,t2いずれもs1,s2という2つのリソースを占有できずに永遠に処理が進まない

おまけ1

件のコードでのsynchronizedについて一応解説します

Test.executeのsynchronized

Test.execute についてるsynchronizedは、実際のところ別インスタンスなので意味はありません。
ミスリードのために付けたのかもしれません。

Sample.hello および Sample.bye のsynchronized

s1.hello(t1)s1.hello(t2) など同時実行されることはありますが、既に論じられている通りこれらが直接デッドロックの原因になるわけではありません。
ならば意味がないかというとそんなことはなく、アトミック性や可視性を担保するために必須となります。

アトミック性

これがないと例えば、
t1スレッドでthis.test == nullがtrue判定されてからthis.test = test;が実行される間に、t2スレッドでもthis.test == nullをtrue判定し、
s1.test == t1 となった直後に s1.test == t2 と上書き処理され、2スレッドで同時に s1.hello がtrueを返すような不整合状態が起こりえます。

可視性

これがないと、それぞれのスレッドが最新のデータを見ない可能性があります。

例えば
t1スレッドで s1.hello(t1) を実行した結果 s1.test == t1 の状態になったが
t2スレッドが最新のデータを読まずにローカルキャッシュの s1.test == null をそのまま用いて s1.hello(t2) を実行すると不整合状態になりえます。

おまけ2

melianさんが挙げられている記事について
https://qiita.com/hanohrs/items/d0d3a5288db10b69d2a4#13-%E7%AB%A0-%E5%95%8F%E9%A1%8C-33

  1. スレッド1が s1.hello() を実行し、s1.test が非 null になる
  2. スレッド2がスレッド1が書き換えた s1.test を参照し、非 null なので、while ループを抜けられない
  3. スレッド1が s1.bye() を実行し、スレッド1では s1.test が null に戻る
  4. スレッド2が、s1.test が volatile でないのでスレッド1が更新した値を読むことができず、非 null の値を読み続けて while ループを抜けられない

t1:s1.hello を実行
t2:s2.hello を実行せず s1.hello を実行している (s2.hello を先に実行しているなら 広義のデッドロックで 3.の t1:s1.bye に辿り着けない)

…ということで、これは誤植修正前のコードについて論じていると思われ、
誤った前提(誤植修正前のコードでデッドロックの可能性がある)を元に誤った結論を導き出してしまっています。

ちなみに非デーモンスレッドの終了条件やsynchronized内の可視性あたりの勘違いがあるっぽいので
正直ちゃんと仕様を理解したうえでの推察とかではなく、たんなる想像を書いているのでは?…という気がするのであまり鵜呑みにしない方がよさげです。

スレッド終了…… 書籍のコードだとタイミング問題で先に "end" が出力されてからスレッド処理が継続する場合も普通にある。そもそも誤植修正前の場合絶対にデッドロックが起こらないので単に "end"出力→スレッド2つの処理が正常に終了…となったのを『スレッドの終了を待たずに正常終了してしまう』と勘違いしたのかも。

synchronized内の可視性…… synchronizedは入る時と出る時にローカルキャッシュを捨てて可視性を担保するので、『スレッド2が、s1.test が volatile でないのでスレッド1が更新した値を読むことができず』はあり得ない。

以下05/26時点の書き込み

現状のコードではデッドロックは発生しません。

Test.execute はこのコード内ではスレッド2つがそれぞれ1つずつ別のTestインスタンスを占有する形になっているので特に競合は発生しません。
現状に限れば synchronized が付いていても付いていなくても同じ挙動になります。

残りの問題 Sample の各メソッドについてですが
executeに含まれるforループ内からの呼び出しを、次のようなモデルで説明できます。

  • 2つのスレッド t1,t2 がそれぞれリソース s1,s2 を取り合う
  • 各スレッドは s1->s2 の順にリソースを占有し、両方を占有できたら s2->s1 の順で解放する
  • 片方のスレッドがリソースを占有したら、もう片方は解放を待たねばならない

…なんですが、実はこれはもっとシンプルなモデルで説明ができてしまいます。

  • 2つのスレッド t1,t2 がリソース s1 を取り合う
  • 先に s1 を占有した方が、s2占有 -> s2解放 -> s1解放 を行う
  • 片方のスレッドがリソースs1を占有したら、もう片方は解放を待つ

つまり2つのリソースを扱っていますが、実はスレッドのブロックに関わるのは実質1つのリソースだけであり
デッドロック発生の原因である「2つ以上のリソースが必要な処理で、別々のスレッドがそれぞれ別のリソースを占有したままお互いの解放を待つ」という状況が発生し得ません。


わざとデッドロックを起こしたければ、ループ状の配置となるように

java

1 new Thread(() -> { 2 t1.execute(s1, s2); 3 }).start(); 4 5 new Thread(() -> { 6 t2.execute(s2, s1); //引数の順番入れ替え 7 }).start();

などと変更するとよいです

投稿2024/05/26 03:39

編集2024/05/29 16:17
pecmm

総合スコア612

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

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

ikedas

2024/05/26 07:28 編集

立ち寄った書店に在庫があったので立ち読みしたところ、質問のコードは 志賀澄人『徹底攻略Java SE 11 Gold問題集』インプレス刊 (2033-11-01第1版第5刷) pp.550-551 に掲載のものを書き写したものと思われます。 ただし書籍と当質門では相違点があり、書籍では引数s1、s2がpecmmさんが提案された通りの順序で書かれています。
jimbe

2024/05/26 07:36 編集

>わざとデッドロックを起こしたければ… それで起きるでしょうか…。 私 Gold 持ってませんので何か分かってないんだと思いますが、良かったら教えて頂けると助かります。
tmp

2024/05/26 09:15

>それで起きるでしょうか…。 それぞれが1つ目を取得のt1がs1取得とt2がs2取得となった状態でなりませんか? まあ、Javaはあまり詳しくないですが・・
k.fujisawa

2024/05/26 13:43

丁寧な回答ありがとうございます。
jimbe

2024/05/26 15:26 編集

メソッドに付いている synchronized はそのメソッドを実行する時に this のロックを獲得しようとし、ロックが取れなかったら取れるまで待機し、取れ次第メソッドを実行して、メソッドの終了と共に解放すると理解しています。 Sample の hello() も bye() もメソッド内では何のロックも取りに行きませんので、たとえ t1 と t2 が同時に同じ Sample オブジェクトの hello() もしくは byte() を呼ぶことになったとしても、先にその Sample オブジェクトのロックを獲得したほうがメソッドを実行して解放し、続いてもう一方が獲得して…となるだけで、デッドロックになりようが無さそうに見えます。 質問へのコメントで melian さんが紹介されている Qiita の記事でも最後に書かれていますが、コードの不備(?)的に while が終わらないということはあるかもしれませんが、デッドロックが原因で処理が進まないという状況が見えません。
k.fujisawa

2024/05/26 14:34

おっしゃる通りですね!これはデッドロックではなく、ただの無限ループですね。
k.fujisawa

2024/05/26 14:49 編集

jimbeさんのおかげで解決できたのですが、 ベストアンサーに指定したい回答がありません。 誤りを含んでいるものは、極力避けたいです。
k.fujisawa

2024/05/26 14:59

jimbeさん、よろしければ、回答を挙げてくれませんか?
jimbe

2024/05/26 15:37 編集

ええと、解決…されたんですかね? 個人的にこちらの pecmm さんの最後のデッドロックを起こす修正の件が引っかかっているのでこちらにコメントしたのですけども^^; 書籍の修正も同じようになっているそうですし…。 コピペしておきますね。
k.fujisawa

2024/05/26 16:37 編集

僕は間違った解釈をしてベストアンサーにしたので。申し訳ないです。 以下の説明にある「占有・解放」は、ロックの占有・解放を指すものでないので。 >各スレッドは s1->s2 の順にリソースを占有し、両方を占有できたら s2->s1 の順で解放する >先に s1 を占有した方が、s2占有 -> s2解放 -> s1解放 を行う
tmp

2024/05/26 23:21

ロック機能で待ちになるのがデッドロックなのですね。単純にお互いに待ち状態になるのがデッドロックだとおもってました。ありがとう
jimbe

2024/05/27 04:20

私含め皆さんの回答で「デッドロックでは無い」というのはその「ロック機能による待ち」でのことを言っていますが、 tmp さんの仰る通り書籍の説明の「デッドロックの可能性がある」は「(ロック機能じゃなくても)お互いに待ち状態になる」ことをデッドロックと言っているかも知れませんね。
k.fujisawa

2024/05/30 09:32

05/30 01:15追記分に関しまして "end"の出力は書籍の引用でなく、私自身が追加したものになります。失念しておりました。申し訳ありません。 非デーモンスレッドとmainスレッドの関係。synchronizedの可視性の保証。 勉強できました。ありがとうございます。
k.fujisawa

2024/05/30 10:06

掲題の質問に、書籍の解答を追記しました。 出題者の意図は汲み取れるかと思います。
k.fujisawa

2024/05/30 12:43

"リソース"には、オブジェクトのロックだけでなく、共有メモリ等も含まれると理解しました。 ありがとうございます。
jimbe

2024/05/31 06:08 編集

>書籍の解答を追記しました >>synchronizedによってデッドロックが発生してしまう可能性 解答あったんですね(それもそうか…) 思いっきり synchronized てなっちゃってますけど、やはり何か(私の)知らないモノがあるのか…。
k.fujisawa

2024/05/31 12:27 編集

私も思いっきりなっちゃってると思います。 どうでしょう 書き間違えてるか、認識を間違えてるか 設問を複雑にしようとして失敗したのか 作成者側の問題かなとも思います
jimbe

2024/06/01 08:46

正確さの為に一応補足です。 >コードの書き方の問題 >解放待ちにウェイトも付けず何も処理を入れないならば素直にsynchronizedで待てばよくて、空の無限ループは用いるべきではありません。 第6刷を見た所 while の中に //do something とコメントが入っていましたので、空の無限ループのつもりではなかったようです。
pecmm

2024/06/04 22:53

私も第1版第5刷をチラ見できたんですが、確かにsynchronizedが原因でデッドロックが発生するみたいに書いてありましたね…。 回答としてはライブロックではない(ライブロックだと競合解消のためにリソースの占有/解放は進むけど全体として最終処理に辿り着けず競合…みたいな話なので違う)ですし、デッドロックで間違いない…とは思うんですが 解説が一ヵ所怪しいと全体的にうさんくさく見えてしまいますね……
guest

0

メソッドに付いている synchronized はそのメソッドを実行する時に this のロックを獲得しようとし、ロックが取れなかったら取れるまで待機し、取れ次第メソッドを実行して、メソッドの終了と共に解放すると理解しています。

Sample の hello() も bye() もメソッド内では何のロックも取りに行きませんので、たとえ t1 と t2 が同時に同じ Sample オブジェクトの hello() もしくは byte() を呼ぶことになったとしても、先にその Sample オブジェクトのロックを獲得したほうがメソッドを実行して解放し、続いてもう一方が獲得して…となるだけで、デッドロックになりようが無さそうに見えます。

質問へのコメントで melian さんが紹介されている Qiita の記事でも最後に書かれていますが、コードの不備(?)的に while が終わらないということはあるかもしれませんが、デッドロックが原因で処理が進まないという状況が見えません。

※ Qiita の記事を紹介頂いていたのは melian さんでした。失礼しました、すみません。

投稿2024/05/26 15:26

jimbe

総合スコア13045

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

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

k.fujisawa

2024/05/26 16:01

ロックの説明が適切であるため、ベストアンサーとさせていただきます。
guest

0

結論から言うとこのコードではデッドロックは発生しません。

Test の execute メソッドが synchronized であるため、t1 と t2 の execute メソッドは同時に実行されることはありません。
Sample の hello メソッドも synchronized であるため、同じ Sample インスタンスに対して同時に hello メソッドが実行されることはありません。

つまり、hello メソッドが true を返すためには this.test が null でなければならず、これは他のスレッドがその Sample インスタンスの bye メソッドを呼び出すまで待つ必要があることを意味します。
しかし、Test クラスの execute メソッドが同時に実行されないため、hello メソッドが永遠に true を返さないという状況は発生しません。

したがって、このコードではデッドロックは発生しません。

投稿2024/05/26 01:49

pecchan

総合スコア591

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

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

k.fujisawa

2024/05/26 02:57

> Test の execute メソッドが synchronized であるため、t1 と t2 の execute メソッドは同時に実行されることはありません。 t1 と t2 は別オブジェクトであるため、excuteメソッドは同時に実行されるかと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.40%

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

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

質問する

関連した質問