
Java道|15章のまとめ
1本の処理から、仲間と連携して動く処理へ。
スレッドを学ぶと、Javaプログラムは一本道ではなく、複数の流れが協力して進む立体的な世界として見えてきます。
15章では、Javaプログラムを「1本の処理の流れ」だけで考える段階から、さらに一歩進みました。
これまでの基本的なプログラムでは、main メソッドから処理が始まり、上から下へ順番に実行される流れを中心に学んできました。
main の流れ
↓
処理1
↓
処理2
↓
処理3この考え方は、Javaの基本を理解するうえでとても大切です。
しかし、15章で学んだスレッドを使うと、プログラムの中に複数の処理の流れを作れるようになります。
鬼滅の刃風にたとえると、鬼殺隊本部の任務で、1人の隊士だけがすべてを順番にこなすのではなく、水月、蒼真、記録係、支援隊士がそれぞれ別の役割を持って同時に動くような状態です。
水月は型の修行を進める。
蒼真は作戦の流れを整理する。
記録係は修行記録をまとめる。
支援隊士は道具や回復薬を準備する。
このように、複数の流れが同じプログラムの中で動くようになると、Javaの処理はかなり立体的に見えてきます。
ただし、仲間が増えればそれだけで安全に任務が進むわけではありません。
誰がいつ動くのか。
少し待つ必要があるのか。
仲間の終了を待つ必要があるのか。
同じ修行記録帳をどう安全に使うのか。
こうしたことまで考える必要があります。
15章は、スレッドの基本から、起動、制御、作り方の違い、共有データの安全な扱い方までを学ぶ章でした。ここでは、15章で学んだ内容を、鬼滅の刃風の世界観に置き換えながら整理していきます。
スレッドとは何だったのか
スレッドとは、プログラムの中にある処理の流れです。
これまでの基本的なJavaプログラムでは、main メソッドから始まる1本の流れを中心に考えてきました。
しかし、スレッドを使うと、main の流れとは別に、新しい処理の流れを作れます。
| 考え方 | 鬼滅の刃風のイメージ | 処理の流れ |
|---|---|---|
| 基本的なプログラム | 1人の隊士が順番に任務を進める | 1本 |
| スレッドを使うプログラム | 複数の隊士が別々に任務を進める | 複数本 |
鬼殺隊本部で考えてみましょう。
1本の流れだけなら、支援隊士が次のように順番に作業します。
修行場を準備
↓
型の確認
↓
記録の整理
↓
道具の片付けしかし、複数のスレッドを使うと、次のように分担できます。
main の流れ :支援隊士が修行場を準備
水月スレッド :水月が型の修行を進める
蒼真スレッド :蒼真が作戦の流れを整理する
記録係スレッド :修行記録をまとめるこのように、スレッドは「処理の担当者」を増やすような仕組みです。
ただし、スレッドを使ったからといって、必ず処理が単純になるわけではありません。
複数の流れがあるからこそ、実行順序や共有データへのアクセスに注意が必要になります。
スレッドは複数起動できる
15章で最初に押さえた大切な考え方は、スレッドは1つだけでなく複数起動できるということです。
1つのスレッドを起動すると、main とは別の流れが1本増えます。
さらにもう1つスレッドを起動すれば、流れはさらに増えます。
| start の呼び出し | 増える流れ |
|---|---|
| start を1回呼ぶ | 新しいスレッドが1本増える |
| start を2回呼ぶ | 新しいスレッドが2本増える |
| main も動く | main スレッドも1本の流れとして残る |
たとえば、水月スレッドと蒼真スレッドを起動すると、main を含めて3本の流れになります。
| 流れ | 内容 |
|---|---|
| main スレッド | 支援隊士が本部の準備を進める |
| 水月スレッド | 水月が型の修行を進める |
| 蒼真スレッド | 蒼真が作戦確認を進める |
ここで大切なのは、main が消えるわけではないことです。
新しいスレッドが動き出しても、main は main として処理を続けます。
鬼滅の刃風に言えば、水月が修行へ向かっても、蒼真が作戦確認を始めても、本部の支援隊士は自分の準備を続けています。
図:1本の流れから複数スレッドへ
↓クリックすると拡大表示されます。

この図が示していること
この図は、15章前半で学んだ「処理の流れを増やす」という考え方を表しています。
左側では、main の1本の流れだけで、すべての処理を順番に進めています。
右側では、main スレッドに加えて、水月スレッド、蒼真スレッド、記録係スレッドがそれぞれ別々に動いています。
| 図の要素 | 意味 |
|---|---|
| main | 最初から存在する処理の流れ |
| 1本の矢印 | 順番に進む基本的な処理 |
| 複数のレーン | 複数スレッドによる並行した処理 |
| 水月スレッド | 女性隊士が型の修行を進める流れ |
| 蒼真スレッド | 男性隊士が作戦確認を進める流れ |
この図から分かることは、スレッドは単に速くするための魔法ではなく、処理の担当を分けて、複数の流れとして動かす仕組みだということです。
Thread クラスを継承してスレッドを起動する
スレッドを作る基本的な方法として、Thread クラスを継承する方法を学びました。
基本形は次のようになります。
class DemonSlayerTask extends Thread
{
public void run()
{
// 別スレッドで行いたい処理
}
}この形では、DemonSlayerTask クラス自身が Thread の機能を受け継ぎます。
そのため、DemonSlayerTask のオブジェクトに start を呼び出すことで、新しいスレッドを起動できます。
DemonSlayerTask task1 = new DemonSlayerTask();
task1.start();| 要素 | 役割 | 鬼滅の刃風のイメージ |
|---|---|---|
| extends Thread | スレッドとして動けるクラスにする | 別任務へ出られる隊士の型 |
| run | 別スレッドで行う処理を書く | 任務内容を書いた作戦書 |
| start | 新しいスレッドを起動する | 出撃命令 |
ここで特に大切なのは、run を直接呼ぶのではなく、start を呼ぶことで新しいスレッドが起動することです。
run を直接呼ぶと、普通のメソッド呼び出しになります。
新しい流れは生まれません。
一方、start を呼ぶと、新しい処理の流れが作られ、その流れの中で run が実行されます。
run メソッドは新しい流れの中身
run メソッドは、新しいスレッドで実行したい処理を書く場所です。
たとえば、水月スレッドなら、水月が型の修行を進める処理を run に書きます。
public void run()
{
for(int i = 0; i < 5; i++) {
System.out.println("水月が型の修行を進めています。");
}
}この run が、新しいスレッドの中身です。
| 流れ | 中身 |
|---|---|
| main スレッド | 本部側の処理を進める |
| run のスレッド | 水月や蒼真が個別任務を進める |
複数のスレッドが動くと、画面への表示順が毎回同じになるとは限りません。
水月の表示が先に出ることもあります。
蒼真の表示が先に出ることもあります。
main の表示が途中に入ることもあります。
これは異常ではありません。
複数の流れが独立して進んでいるため、どのスレッドが先に少し進むかは、実行タイミングによって変わります。
鬼滅の刃風に言えば、複数の隊士が別々の場所で動いているので、誰の報告が先に本部へ届くかは毎回同じとは限らない、ということです。
sleep でスレッドを一時停止する
15章では、スレッドを一定時間だけ一時停止する sleep も学びました。
Thread.sleep(1000);1000 はミリ秒です。
つまり、Thread.sleep(1000) は、現在動いているスレッドを1秒間止めるという意味です。
| 書き方 | 意味 |
|---|---|
| Thread.sleep(1000) | 現在のスレッドを1秒止める |
| Thread.sleep(500) | 現在のスレッドを0.5秒止める |
| Thread.sleep(2000) | 現在のスレッドを2秒止める |
ここで大切なのは、止まるのは sleep を実行したスレッドだけだという点です。
プログラム全体が止まるわけではありません。
たとえば、水月スレッドの run の中で sleep を使えば、水月スレッドが一時停止します。
main スレッドの中で Thread.sleep を使えば、main スレッドが一時停止します。
| sleep を書く場所 | 一時停止する流れ |
|---|---|
| run の中 | その run を実行しているスレッド |
| main の中 | main スレッド |
鬼滅の刃風に言えば、水月が一呼吸置いて型を整えていても、蒼真や支援隊士まで一緒に止まるわけではありません。
止まるのは、その場で呼吸を整えている隊士だけです。
join で別スレッドの終了を待つ
sleep が「時間で待つ」処理なら、join は「相手の終了で待つ」処理です。
worker1.join();これは、worker1 のスレッドが終わるまで、join を呼び出した側のスレッドが待つという意味です。
ここで大切なのは、join は相手を止める命令ではないことです。
join は、自分が相手の終了を待つ命令です。
| メソッド | 何を待つか | 鬼滅の刃風のイメージ |
|---|---|---|
| sleep | 指定した時間 | 一呼吸置いてから再開する |
| join | 別スレッドの終了 | 仲間の任務完了を待ってから進む |
たとえば、main の中で worker1.join() を実行した場合、待つのは main スレッドです。
worker1 は止められるわけではありません。
worker1 は自分の run を最後まで進めます。
main は worker1 が終わるまで待ちます。
鬼滅の刃風に言えば、支援隊士が水月に「止まれ」と命じているのではありません。
支援隊士が「水月の修行が終わるまで、こちらは最終確認を待とう」としている状態です。
sleep と join の違い
sleep と join は、どちらもスレッドの流れを調整するために使います。
しかし、待つ理由が違います。
| メソッド | 待つ理由 | 再開する条件 |
|---|---|---|
| sleep | 指定時間だけ待つ | 指定時間が過ぎる |
| join | 指定したスレッドの終了を待つ | 相手のスレッドが終わる |
この違いはとても重要です。
sleep は時間による待機です。
join は仲間の完了による待機です。
鬼滅の刃風に言えば、sleep は「一呼吸置く」ことです。
join は「仲間の任務完了を確認するまで待つ」ことです。
図:sleep と join でスレッドの流れを整える
↓クリックすると拡大表示されます。

この図が示していること
この図は、15章中盤で学んだ sleep と join の違いを表しています。
左側の sleep では、水月スレッドが Thread.sleep(1000) の場所で一時停止します。
止まるのは、sleep を実行している水月スレッド自身です。
右側の join では、main スレッドが蒼真スレッドの終了を待っています。
蒼真スレッドは止められているわけではなく、自分の run を最後まで進めます。
| 図の要素 | 意味 |
|---|---|
| sleep | 現在のスレッドを指定時間だけ止める |
| join | 指定したスレッドの終了を待つ |
| 砂時計アイコン | 一時停止や待機 |
| 水月スレッド | sleep で一呼吸置く処理 |
| main スレッド | join によって仲間の終了を待つ処理 |
この図から分かることは、sleep と join はどちらも待機に関係しますが、待つ理由と止まる側が違うということです。
スレッドの作成方法は1つではない
15章では、スレッドの作り方が Thread クラスの継承だけではないことも学びました。
もう1つの方法が、Runnable インターフェイスを実装する方法です。
| 方法 | 書き方 | 特徴 |
|---|---|---|
| Thread クラスを継承する | extends Thread | 分かりやすく、基本を理解しやすい |
| Runnable インターフェイスを実装する | implements Runnable | ほかのクラス継承と両立しやすい |
Thread 継承では、クラスそのものがスレッドとして動けます。
class DemonSlayerTask extends Thread
{
public void run()
{
// 別スレッドで行う処理
}
}この場合は、作成したオブジェクトに start を呼び出せます。
DemonSlayerTask task1 = new DemonSlayerTask();
task1.start();一方、Runnable を使う場合は、Runnable 実装オブジェクトを Thread に渡して起動します。
class DemonSlayerTask implements Runnable
{
public void run()
{
// 別スレッドで行う処理
}
}
DemonSlayerTask task1 = new DemonSlayerTask();
Thread th1 = new Thread(task1);
th1.start();Runnable 方式では、task1 自身に start を呼ぶのではありません。
start を呼ぶのは Thread オブジェクトである th1 です。
| オブジェクト | 役割 |
|---|---|
| Runnable 実装オブジェクト | 別スレッドで行う処理内容を持つ |
| Thread オブジェクト | その処理内容を新しいスレッドとして起動する |
鬼滅の刃風にたとえると、Runnable 実装オブジェクトは「任務内容が書かれた指令札」を持つ隊士です。
ただし、その指令札だけでは任務は始まりません。
Thread という出撃役に渡し、Thread に start を呼び出して、初めて新しい流れとして動き出します。
Runnable が必要になる理由
Runnable が重要なのは、Javaではクラスの多重継承ができないからです。
Javaでは、1つのクラスが同時に複数のクラスを継承することはできません。
| 状況 | Javaで可能か |
|---|---|
| 1つのクラスを継承する | 可能 |
| 2つ以上のクラスを同時に継承する | 不可能 |
| クラスを継承しつつインターフェイスを実装する | 可能 |
たとえば、あるクラスがすでに記録係の親クラスを継承している場合、さらに Thread クラスを継承することはできません。
しかし、Runnable インターフェイスなら実装できます。
class TrainingRecorder extends RecordKeeper implements Runnable
{
public void run()
{
// 記録整理の処理
}
}鬼滅の刃風に言えば、水月がすでに「記録係の流派」を受け継いでいる場合でも、「別任務で動く約束」である Runnable は身につけられるということです。
このように、Runnable はクラス設計を柔軟にするために役立ちます。
複数スレッドでは共有データに注意が必要
15章の後半で特に重要だったのが、共有データの扱いです。
スレッドを複数動かすだけなら、処理の流れが増えるという理解で進められます。
しかし、複数のスレッドが同じデータを読み書きし始めると、値の食い違いが起こる可能性があります。
たとえば、鬼殺隊本部に共通の修行記録帳が1冊だけあるとします。
水月も蒼真も、その修行記録帳に自分の修行ポイントを加算します。
加算処理は、見た目には単純です。
total = total + 50;しかし、考え方としては次の3段階に分かれます。
| 手順 | 内容 |
|---|---|
| 1 | total の現在値を読む |
| 2 | 読んだ値に50を足す |
| 3 | 結果を total に書き戻す |
この途中で別のスレッドが割り込むと、古い値を読んでしまい、片方の更新が消えたような結果になることがあります。
| 水月スレッド | 蒼真スレッド | total |
|---|---|---|
| total を読む → 0 | 0 | |
| total を読む → 0 | 0 | |
| 0 + 50 = 50 | 0 | |
| 0 + 50 = 50 | 0 | |
| total に50を書く | 50 | |
| total に50を書く | 50 |
本来なら100になってほしい場面でも、結果が50になる可能性があります。
このような問題は、複数スレッドが同じ共有資源を同時に扱うことで起こります。
synchronized による同期が必要になる理由
共有データの矛盾を防ぐために使うのが synchronized です。
メソッドに synchronized を付けると、そのメソッドをあるスレッドが実行している間、ほかのスレッドは同じメソッドに入れなくなります。
public synchronized void addPoint(int p)
{
int tmp = total;
tmp = tmp + p;
total = tmp;
}これにより、total を読む、計算する、書き戻すという一連の処理が、途中で割り込まれにくくなります。
| 用語 | 意味 |
|---|---|
| 同期 | スレッドどうしの処理タイミングを整える仕組み |
| 排他制御 | 同時に1つのスレッドしか入れないようにする仕組み |
| synchronized | Javaで排他制御を行うための指定 |
鬼滅の刃風に言えば、修行記録帳に青白い結界を張るようなものです。
水月が書いている間は、蒼真は待つ。
水月が書き終わったあと、蒼真が更新後の合計を見て書く。
このように、1人ずつ順番に記録することで、修行ポイントの合計を正しく保てます。
synchronized が守るものと守らないもの
synchronized を付けると、共有データを扱う処理を排他的に実行できます。
ただし、すべての実行順序を完全に固定するわけではありません。
| synchronized が守ること | synchronized が固定しないこと |
|---|---|
| 共有データを扱うメソッドへの同時侵入を防ぐ | スレッド全体の実行順序 |
| 読む、計算する、書き戻す流れを守る | どちらのスレッドが先に動くか |
| 更新の整合性を守る | 画面表示のすべての順番 |
つまり、synchronized は「共有データの正しさを守るための仕組み」です。
表示順を完全に固定するためのものではありません。
ここを混同しないことが大切です。
図:15章全体の学習内容
↓クリックすると拡大表示されます。

この図が示していること
この図は、15章で学んだ内容を1つの流れとして整理しています。
最初に、スレッドとは処理の流れを増やす仕組みだと学びました。
次に、Thread クラス、run、start を使って新しいスレッドを起動する方法を学びました。
その後、sleep で一時停止し、join で別スレッドの終了を待つ方法を学びました。
さらに、Runnable によってスレッドの作成方法が1つではないことを理解しました。
最後に、synchronized によって共有データを安全に扱う必要があることを学びました。
| 学習内容 | 理解したこと |
|---|---|
| スレッドの基本 | 処理の流れは複数持てる |
| Thread と run | 別スレッドで動く処理を書く |
| start | 新しいスレッドを起動する |
| sleep | 時間で待つ |
| join | 仲間の終了を待つ |
| Runnable | 処理内容と起動役を分ける |
| synchronized | 共有資源を守る |
この図から分かることは、15章が「スレッドを起動して終わり」の章ではなかったということです。
スレッドを作る、増やす、止める、待つ、作り方を選ぶ、共有データを守る。
これらが1つの流れとしてつながっています。
15章で使われたオブジェクト指向の考え方
15章はスレッドの章ですが、その中でもオブジェクト指向の考え方が自然に使われていました。
スレッド用のクラスを作る。
そのクラスからオブジェクトを作る。
run や addPoint のようなメソッドを使う。
Thread を継承する。
Runnable を実装する。
これらはすべて、Javaのオブジェクト指向とつながっています。
鬼滅の刃風に整理すると、次のようになります。
| オブジェクト指向の要素 | 鬼滅の刃風のたとえ |
|---|---|
| クラス | 隊士の設計図 |
| オブジェクト | 実際に任務へ出る水月や蒼真 |
| フィールド | 隊士が持つ名前や修行ポイント |
| メソッド | 隊士が行う動作 |
| 継承 | もとの型を受け継いで新しい隊士クラスを作る |
| インターフェイス | 守るべき行動の約束 |
Thread クラスを継承する方法では、隊士クラスそのものが「別スレッドとして動ける性質」を受け継ぎます。
Runnable を実装する方法では、「別スレッドで行う処理内容」という約束を守る形になります。
このように、スレッドの学習は、単に並行処理だけでなく、クラス設計の考え方とも深く関係しています。
15章を学んで見えるようになること
15章を学ぶ前は、Javaプログラムは1本の一本道として見えやすかったはずです。
しかし、15章を学ぶと、次のような視点が加わります。
| 見えるようになること | 内容 |
|---|---|
| main 以外の流れ | どこで新しいスレッドが生まれるか |
| run の役割 | 別スレッドで何をするか |
| start の意味 | 新しい流れを起動する場所 |
| sleep の意味 | どのスレッドが時間で待つか |
| join の意味 | どのスレッドが誰の終了を待つか |
| Runnable の意味 | 処理内容と起動役を分ける考え方 |
| synchronized の意味 | 共有データを守る必要性 |
鬼殺隊の任務で考えると、ただ「誰かが動いている」と見るだけでは不十分です。
今、水月は何をしているのか。
蒼真はどの流れで動いているのか。
支援隊士は待っているのか。
記録係は共有の修行記録帳を安全に使えているのか。
このように、複数の流れを見分け、タイミングを整理し、共有資源を守る視点が必要になります。
Javaのスレッドも同じです。
15章で身についた力
15章で身についた力を整理すると、次のようになります。
| 身についた力 | 内容 |
|---|---|
| 流れを複数本で考える力 | プログラムを一本道だけで見ない |
| スレッドを作る力 | Thread 継承や Runnable 実装を理解する |
| スレッドを起動する力 | start で新しい処理の流れを作る |
| スレッドを制御する力 | sleep や join で動きを調整する |
| 共有データを守る力 | synchronized で安全性を保つ |
| オブジェクト指向で整理する力 | クラス、オブジェクト、メソッドの役割を見分ける |
15章は、Javaをより実践的に使うための大切な入口です。
スレッドを知ることで、時間のかかる処理を別の流れに分けたり、複数の処理を並行して進めたりできるようになります。
そして同時に、複数の流れがあるからこそ、待つ、終了を確認する、共有データを守る、といった考え方も必要になります。
鬼滅の刃風に言えば、強い隊士が増えるだけでは任務は成功しません。
水月、蒼真、記録係、支援隊士がそれぞれ動きながら、必要なところで待ち、順番を守り、共通の記録を正しく扱うことで、任務全体が安全に進みます。
Javaのスレッドも同じです。
複数の流れを作る力と、それらを安全に協調させる力。
この2つがそろうことで、スレッドは本当の意味で実用的な技術として使えるようになります。
