1. スレッド¶
1.1. スレッドとは¶
スレッドとは、プログラムを実行している主体です。すべてのプログラムはスレッドによって実行されています。 1つのスレッドは、ひとりの人間がプログラムを1行ずつ読んでプログラムの流れを追いかけるように、命令を1つずつ解釈し処理を実行していきます。
スレッド(Thread)とはもともと「糸」という意味ですが、プログラムの実行は、糸をたぐるように順番に命令が実行されていくため、そのような名前がついています。 1つのスレッドはあくまでも1本の糸であり、2つの処理を同時に行うことはありません。
Javaのプログラムを起動するには、次のように、javaコマンドにおいて実行したいクラスの名前を指定していました。
java SomeClass
javaコマンドが実行されると、Java仮想マシンは新しいスレッドを作成し、そのスレッドによって指定したクラスのmainメソッドが実行されます。 スレッドはmainメソッドの最初から順番に命令を実行していき、mainメソッドの実行が終了するとスレッドは消滅します。
スレッドとは1つの処理の流れを示す単位です。ちなみに「thread」を翻訳すると「糸や筋」といった意味になります。「1つの話の流れ」と言う意味で掲示板などで話題のことをスレッドと読んだりしています。
javaは複数のスレッドを同時実行させて並列処理(マルチスレッド)を可能にしています。
よく似た処理単位として「プロセス(並列処理をさせることで「マルチプロセス」)」がありますが、プロセスはOSにインストールされたソフトウェア(プログラム)の実行単位であり、スレッドはそのプログラム中の一連の処理のような感じになります。その他、プロセスは固有のメモリ空間を持ちますが、スレッドはメモリ空間を共有するという違いがあります。したがって「マルチスレッド」は「マルチプロセス」に比べ並列処理を制御する負荷は軽くなりますが、メモリ内の変数などに対して排他制御等の考慮が必要になってきます。
1.2. マルチスレッド¶
Javaはマルチスレッドを取り扱うことのできる言語です。マルチスレッドとは複数のスレッドという意味です。 つまりJavaでは複数の人が同時に仕事をするように、複数のスレッドを同時に実行することができるのです。
たとえば、1つのプログラムの中で、通信処理を行いながら、同時に計算処理を行うことなどができます。 このような複数のスレッドを取り扱うプログラムを作成することを、「マルチスレッドプログラミング」といいます。
ところで、多くのコンピュータはCPUを1つしかもっていません。そのようなコンピュータでは、厳密には1つの処理しか同時には実行することができません。 そこで、「マルチスレッド」では、通常「時分割処理」という方法が用いられています。 「 時分割処理 」とは、 短い時間間隔で実行する処理を切り替える方法です。 複数の処理を頻繁に切り替えて実行することで、仮想的に複数の処理を同時に実行しているように見せかけています。
以下参照:IT専科 マルチスレッド処理は各スレッド(=各処理)に対してCPUの資源をタイムスライス(時分割)という技術を使って分け合うことで実現しています。例えば、「処理A」、「処理B」、「処理C」と処理していく場合、次のようなイメージになります。

シングルスレッドでは「処理A」、「処理B」、「処理C」と順に処理しているのに対して、マルチスレッドでは処理を細かく分割して、先の処理が終了するのを待たずに次々処理を行っています。これによりあたかも並列処理をしているかのようにみえる訳です。
しかしこのままのイメージだと、複数のスレッドがCPUを時分割で使用したところで、各処理の終了する順番が変わることがあってもスループット(応答速度)は変わりません。 むしろ処理分割する分遅くなります!
それではどのようなときにマルチスレッドが有効なのでしょうか。それは次のように各処理の負荷の差が大きい場合です。

上記の場合、シングルスレッドでは「処理A」が終了するまで「処理B」、「処理C」は処理されません、つまりシステムからの応答が返ってきません。したがって負荷の高い処理が行われるといちいち待たされるような感じになります。 これに対してマルチスレッドの場合、負荷の大きい処理が先に起動しても、その終了するのを待つことなく次々と軽い処理が先に終了して結果を返すことができる為、スループットが向上します!
以上の結果からマルチスレッド処理とは、 高負荷の処理が入っても応答をとめることなく、次の処理を進めたい場合に有効な技術といえます。
1.3. スレッドのライフサイクル¶
Javaのスレッドは、作成されてから消滅するまでにいくつかの状態を遷移していきます。状態の遷移を図に表すと、次のようになります。


初期状態¶
新しいスレッドを作成した状態です。この状態ではまだスレッドは動作していません。次の章で説明するstart メソッドにより、実行可能状態となります。
実行可能状態¶
スレッドが動作/起動(startメソッド)している状態です。この状態は、さらに「実行中」と「実行準備完了」の2つの状態に分けられます。「実行中」は、時分割処理によって実際にCPUによって処理が実行されている状態です。通常のCPUが1つしかないコンピュータでは、「実行中」のスレッドは同時には最大で1つだけしか存在しません。その他のスレッドは「実行準備完了」状態で、CPU時間が割り当てられるのを待機しています。
実行状態¶
CPU資源を使用して処理を行っている状態です。次の3つの場合により遷移先が異なります。
- より優先順位の高いスレッドがきたとき。「実行可能状態」に遷移します。
- wait()、sleep()メソッドが実行されたときや入出力等に伴う処理の遅延が発生したとき、その他、排他制御でロックされているとき「待機状態」に遷移します。
- 処理が完了したとき「終了」となります。
ブロック状態【待機状態】¶
ディスクの入出力操作や、スレッドの排他制御や同期処理などにより、スレッドの動作が一時的に休止している状態です。ブロック状態となっている原因が解消されれば「実行可能状態」に戻ります。スレッドは、動作中に何度も「実行可能状態」と「ブロック状態」を行き来することができます。
終了状態¶
スレッドの処理が終了した状態です。一度終了状態になったスレッドは、再び動作を開始することはありません。
1.4. 複数のスレッドの関係¶
複数のスレッドがそれぞれまったく関係ない処理をしているときは、特にそれらのスレッド間の関係を意識する必要がありません。しかし、複数のスレッドが同じオブジェクトを操作したり、協調して処理を行う場合には、スレッド間の相互作用に注意しなければいけません。
ある処理を、他のスレッドに邪魔されないようにあるスレッドだけで独占して実行することを「排他制御」といいます。また、複数のスレッド間で待ち合わせしたり、処理のタイミングを合わせることを「同期」といいます。Javaでは排他制御や同期を行うためのさまざまな方法が用意されています。