Threadは生成・開始・待機を分ける
new Thread(...)はスレッドのオブジェクトを作ります。渡した処理を開始する操作はstart()です。run()を直接呼ぶ場合は通常のメソッド呼び出しであり、新しいスレッドを開始しません。join()は対象スレッドの終了を待ちます。sleep()は現在実行中のスレッドを一定時間待機させます。- 一度開始したThreadは、終了を待ってからでも再び
start()できません。
出力の問題では、まずjoin()などが保証する前後関係を見つけます。実行して一度同じ順序になっただけでは、毎回その順序になる証明にはなりません。基本の違いはJava SE 17のThread APIで確認できます。
ExecutorServiceとFutureの役割
ExecutorServiceはタスクの実行を管理します。submitが返すFutureでは結果や完了を確認できます。Runnable自身は値を返さず、Callable<V>はV型の値を返し、検査例外も宣言できます。
| 操作 | 確認する点 |
|---|---|
Future.get() | 必要なら完了まで待ちます。引数のないgetに固定のタイムアウトはありません。 |
shutdown() | 新しいタスクを受け付けなくなります。投入済みのタスクは実行されますが、この呼び出し自体が全タスクの完了を待つわけではありません。 |
shutdownNow() | 実行中のタスクの停止を試みます。割込みに応答しない処理を含め、必ず即座に停止するという保証はありません。 |
Java 17では、ExecutorServiceを後のJavaバージョンの例と同じようにtry-with-resourcesで使えると考えないでください。対応バージョンはJava SE 17のExecutorService APIを基準にします。
例題2問:再開始とshutdown後のタスク
「開始できる回数」と「終了を要求した時点ですでに投入されているタスク」を確認して答えてください。
例題1:Threadを再開始できるか
次の処理が最後に表示する内容を選んでください。必要なimportは記述済みです。
Thread t = new Thread(() -> {});
t.start(); t.join();
try { t.start(); System.out.print("restarted"); }
catch (IllegalThreadStateException e) { System.out.print("one-start"); }
1つ選択してください
- A.
one-start - B.
restarted - C.
コンパイルエラー - D.
IllegalStateException
例題1の正解・解説を見る
正解:A
正解は「one-start」です。
一度開始したThreadは、終了後でも再びstartできません。再実行には新しいThreadなどを使います。
- A:一度開始したThreadは、終了後でも再びstartできません。再実行には新しいThreadなどを使います。
- B:この結果にはなりません。一度開始したThreadは、終了後でも再びstartできません。再実行には新しいThreadなどを使います。
- C:この結果にはなりません。一度開始したThreadは、終了後でも再びstartできません。再実行には新しいThreadなどを使います。
- D:この結果にはなりません。一度開始したThreadは、終了後でも再びstartできません。再実行には新しいThreadなどを使います。
確認するポイント:joinで終了を待ってもThreadが新品の状態へ戻るわけではありません。
仕様を確認するための公式資料:
問題ID:jg17-08ad887b7923d2 · この問題の訂正を連絡する
例題2:shutdown後の既存タスク
次の処理が最後に表示する内容を選んでください。必要なimportは記述済みです。
var pool = Executors.newSingleThreadExecutor();
try {
var a = pool.submit(() -> "A");
var b = pool.submit(() -> "B");
pool.shutdown();
System.out.print(a.get() + b.get());
} finally { pool.shutdown(); }
1つ選択してください
- A.
A - B.
RejectedExecutionException - C.
TimeoutException - D.
AB
例題2の正解・解説を見る
正解:D
正解は「AB」です。
shutdownは新規投入を拒否しますが、既に投入したタスクは実行されます。引数なしgetに固定のタイムアウトはありません。
- A:この結果にはなりません。shutdownは新規投入を拒否しますが、既に投入したタスクは実行されます。引数なしgetに固定のタイムアウトはありません。
- B:この結果にはなりません。shutdownは新規投入を拒否しますが、既に投入したタスクは実行されます。引数なしgetに固定のタイムアウトはありません。
- C:この結果にはなりません。shutdownは新規投入を拒否しますが、既に投入したタスクは実行されます。引数なしgetに固定のタイムアウトはありません。
- D:shutdownは新規投入を拒否しますが、既に投入したタスクは実行されます。引数なしgetに固定のタイムアウトはありません。
確認するポイント:shutdownNowとの違いと、タスク投入のタイミングを確認します。
仕様を確認するための公式資料:
問題ID:jg17-54c1c031c5f915 · この問題の訂正を連絡する
並列処理の61問で復習する
問題演習の「出題分野」で「並列処理」を選ぶと、61問の演習ができます。61問は本サイトの収録数で、試験の出題比率ではありません。
基本を確認したら、同期・ロック・Atomic・並列コレクションへ進みます。「競合を防げる範囲」「可視性」「処理全体が不可分か」を分けて説明できるか確かめましょう。Streamを並列化する問題はStream APIの要点と併せて復習できます。
次に取り組む学習
- Java Gold 17の勉強法・復習計画で学習順序を決める。
- Stream APIの解説・例題で処理の流れを確認する。
- モジュールシステムの解説・例題で公開範囲を整理する。
問題は本試験の過去問ではなく、Java SE 17を学ぶためのオリジナル練習教材です。編集・訂正の方針をご確認ください。