公式アカウントからの投稿が始まります

Java Gold8の参考書を読んでいて疑問に思ったことが解決できません。
どなたか下記お分かりになる方がいらっしゃいましたら、教えて頂けないでしょうか。

1.スレッドの実行順序の謎

Java Gold SE8 (山本道子著)でのスレッドの章P372で下記のプログラムが記載されています。

public class Sample10_4 {
public static void main(String[] args){
Thread threadA = new Thread(() -> {
System.out.println("threadA : sleep 開始");
try {
Thread.sleep(5000); //ThreadAスレッドのsleep
} catch (InterruptedException e) {
System.out.println("threadA : 割り込みをキャッチしました");
}
System.out.println("threadA : 処理再開");
});
threadA.start();

try {
System.out.println("main : sleep 開始");
Thread.sleep(2000); // mainスレッドのsleep
System.out.println("main : sleep終了");
threadA.interrupt(); // スレッドへ割り込み
}catch (InterruptedException e){
System.out.println("main : 割り込みをキャッチしました");
}
}
}

結果は次のようになります。
main : sleep 開始
threadA : sleep 開始
main : sleep終了
threadA : 割り込みをキャッチしました
threadA : 処理再開

私が分からないのは下記の点です。
(1)threadA.start();が先に記載されていて、コーディング上はこちらが先にキックされているように見えるのですが、なぜmainメソッドのSystem.out.println("main : sleep 開始");が先に実行されているのでしょうか。暗黙でmainの方が先に処理されるのだとしたら、threadA.start();がスタートされるタイミングはどこでキックされているのかと言うことを、コーディング上のどこで判断すれば良いでしょうか。

(2)同著P373で、「5〜12行目によりmainスレッドがthreadAスレッドを開始します」とさらっと書いてあるのですが、こうした通常のプログラミングにおいて、mainメソッド=mainスレッドという扱いなのでしょうか。私の目から見れば、mainメソッドからthreadAと言うスレッドがキックされたと言うように見えるので、飽くまでmainメソッドはスレッドではなくてmainメソッドだと初見は感じるのです。今まで使用していたpublic static void mainと言うのはメソッドでありながらスレッドでもあるのでしょうか。

(3)スレッド処理の順番制御についての考え方で疑問なのですが、時分割処理において短い時間感覚で実行する処理を切り替えていて、あたかもCPUが2つの処理を同時並行で行っているかのように見せる処理だと理解しています。スレッドAとスレッドBが用意されたならば、それはシングルスレッドではなく、擬似的に同時処理をしているかのように見せたマルチスレッドを想定していると考えているのです。
 スレッド制御メソッドにおいては、自身の実行状態を停止し、他のスレッドに実行するよう一時的に身を引かせるyield()や、逆に他のスレッドが実行していようが割り込みをかけるinterrupt()など、その優先順位や順番づけに働きかけるようなメソッドが用意されています。
これはシングルスレッド処理であれば理解はできます。一つのCPUのシングルスレッドに対し、どういう制御をスケジューラに渡して、スケジューラがどのような順番で実行するのか、と言うことを判断するからです。
 しかし、スレッドを立てて、複数の処理を時分割処理で同時進行させるマルチスレッドにおいては、その制御をする意味が分からないのです。スレッドAとスレッドBが用意されて同時進行させるならば、両方共少しづつ処理が進むので、yield()やinterrupt()、あるいは処理が終わるのを待つjoin()などは不要ではないかと一般的に思うのです。

 おそらくはスレッドにおける理解が不足しているためにこうした疑問点が湧いていると思うのですが、どうしてこうなっているのかを自分で調べても分かりませんでした。
 どなたかお分かりになる方がいらっしゃいましたら教えて下さい。

A 回答 (3件)

>threadA.start();が先に記載されていて、コーディング上はこちらが


>先にキックされているように見えるのですが、なぜmainメソッドの
>System.out.println("main : sleep 開始");が先に
>実行されているのでしょうか。

threadA.start()はスレッドの開始を準備するだけで、いつ
開始するのかはスケジューラ任せです。

>mainメソッド=mainスレッドという扱いなのでしょうか。

メインスレッドとは java のプロセスが最初に作るスレッド。
mainメソッドはメインスレッドで実行さえれます。

>時分割処理において短い時間感覚で実行する処理を切り替えていて、
>あたかもCPUが2つの処理を同時並行で行っているかの
>ように見せる処理だと理解しています。

そういう動きもしますが、今の CPU はスレッドが数個までなら
物理的に同時に実行できます。

>yield()やinterrupt()、あるいは処理が終わるのを待つ
>join()などは不要ではないかと一般的に思うのです。

yield()は一時的にスレッド実行優先順位を下げたいときに
使いますが、まず使われることはありません。
スレッドのかなり上級者向けの機能です。

interrupt()は実行中断しているスレッドを強制的に起こすのに
使います。例えばサービススレッドが要求待ちで
ブロックしている場合、スレッドを起こして確実に終了処理を
実行させて終了させる などの用途に使います。

join はスレッドの終了を待つのに使います。
例えば、スレッドA, B の計算処理が完了しないと スレッドC
の計算処理が起動できない場合 join で待ってから
スレッドCを起動します。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

>開始するのかはスケジューラ任せです
ああ〜なるほど。コーディング順序では実際に処理が実行されるタイミングが計れない、と。

>メインスレッドとは java のプロセスが最初に作るスレッド。
>mainメソッドはメインスレッドで実行さえれます。
これ誰も言って無かった&今までの書籍に書いてなかった話なので(もしかして書いてあったか?)、今も疑心暗鬼なのですが、そうなのですね。

丁寧に回答ありがとうございました。

お礼日時:2020/12/11 23:40

>これ誰も言って無かった&今までの書籍に書いてなかった


>話なので(もしかして書いてあったか?)、
>今も疑心暗鬼なのですが、そうなのですね。

まだあまり詳しい資料を読んでいないみたいですね。

ひとつ忠告しておくと、マルチスレッドには実行制御や
デッドロック問題の他に
メモリモデルという、結構ややこしくて重たい話題も有って
これらを充分理解していないうちは手を出さない方が良いです。

でないと3ヶ月に1回誤動作するプログラムとか
インテル系CPUでは動くのに他のCPUでは動かない
なんてプログラムが簡単に書けてしまいます。

魔界の仕組みを充分に知るまでは
充分注意して下さい。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
魔界! 是非その中身を知りたい〜。
この書籍が悪いのか、既にこのスレッドの章は魔界だと思っていましたが、更にその先があるんですね。
色々と教えて頂きありがとうございました。

お礼日時:2020/12/17 20:51

とりあえずスレッドについてはたとえば


https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%AC …
を参照のこと.

スレッドは「それぞれが勝手に処理を進める」と思えばいい. だから (1) は厳密にいうと「こんなふうになることもある」でしかない (Java の実装でどうなっているかは知らんけど「スレッド」本来の意味でいえば他のようになる可能性もある) し, (3) についていえば「それぞれが勝手に処理を進める」のであって「複数の処理を時分割処理で同時進行させる」と解釈してはいけない. スレッドを人だと思って「5人が 100 m を走って同時にゴールする」という状況を考えてみよう. あなたは「それぞれの人が同じように走るから何もしなくても (ほぼ) 同時にゴールする」と思っているのかもしれないけど, 実際にはそうではない. 足の速い人もいれば遅い人もいるので, 「同時にゴール」しようと思ったらてきとうに調整しないといけない. そのあたりが同期メソッドの役割.

ついでに (2) は... ん~, 「mainスレッド」という表現がよくない気がする. 「メインスレッド」とすべきだろう. イメージとしては「プログラムを始めるときに『メインスレッド』を起動」して, その「メインスレッド」で main メソッドを実行する. main メソッドから単純に他のメソッドを呼び出すならその呼び出されたメソッドも「メインメソッド」で実行されるし, Thread を使って明示的に新たなメソッドを作ることもできる.
    • good
    • 1
この回答へのお礼

早期の回答ありがとうございました。
うーん、分かったような分からないような・・・(特に(2))。
我々が普通に使っていたmainの前段の処理は暗黙的にスレッド扱いなのかと言うのが衝撃だったが、未だ「本当にそうなのか?」という感じで実感が湧かない状態ですね。

時分割処理は考えない方が良いと言うアドバイスはありがとうございました。
飽くまでスレッド間における処理優先順位とその調整の仕方、と言うように捉えました。

お礼日時:2020/12/11 23:37

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