Javaでマルチスレッドプログラミング -スレッドの優先度と休止と中断-

Javaでマルチスレッドプログラミングを覚えようと、こちらのサイトを読んで写経してみた。前回の記事に引き続き、今回はスレッドの優先度・休止・中断について。
 

スレッドの優先度

すべてのスレッドは優先度を持っている。資源が競合した際、高い優先度を持つスレッドの方が優先的に実行される。スレッドの優先度はgetPriorityメソッドで取得する事ができる。
優先度を設定するにはsetPriorityメソッドを使う。引数に優先度を表す数字を指定する。この値は「Thread.MAX_PRIORITY」「Thread.MIN_PRIORITY」というクラス変数で定義されている最小値(1)から最大値(10)の範囲に収まるものでなければならない。なおデフォルトで与えられる優先度は「5」であり、この値は「Thread.NORM_PRIORITY」クラス変数に定義されている。
しかし、優先度の違いによる資源の割り当て方は、OSやJava仮想マシンの実装に大きく依存する。そのため、高い優先度を設定すると、ある程度は優先的に実行されるかもしれないが、もしかしたら実際には全く優先されないかもしれない。
 

スレッドの休止と中断

ここでは、スレッドの処理を一時休止したり、他のスレッドに割り込みをかけるためのメソッドを説明する。
 

sleep()

sleepメソッドはThreadクラスのクラス(static)メソッドである。sleepメソッドは指定した時間だけ現在実行中のスレッドを休止させる。sleepメソッドはクラスメソッドのため、sleepメソッドを実行するスレッド以外の別のスレッドを休止することはできない。
 
sleepメソッドでの時間の指定方法は以下の2種類となる。

sleep(long millis);
sleep(long millis, int nanos);

 
sleepメソッドを呼び出したスレッドは、取得しているロックを解放しない。ロックを確保したままsleepを実行すると、そのロックを取得したいスレッドを必要以上に待たせてしまうおそれがある。ロックを解放した状態でスレッドを休止させたいときは、waitメソッドを利用することを検討する。
 
スレッドは、sleepメソッドで指定した時間経過しても直ちに動作を再開するわけではない。指定した時間経過後、動作可能な状態にはなるが、他のスレッドがなにか処理を実行中の場合、そのスレッドの実行が継続される。
 
sleepメソッドは、休止中に他のメソッドから割り込みがかけられたときにInterruptedExceptionが発生するので、例外処理を記述しなければならない。割り込みは、あとで説明するinterruptメソッドによって発生させることができる。
 

yield()

yieldメソッドは、現在処理中のスレッドを一時休止し、他のスレッドに実行の機会を与える。Java仮想マシンが複数のスレッドにどのように時間を割り当てるかというのは、実装によって様々である。実装によっては、他にも実行可能なスレッドがあるにもかかわらず、あるスレッドからなかなか処理が移らないということがある。そのようなことを防ぐためにyieldメソッドを用いる。
 

interrupt()

interruptメソッドは休止中のスレッドに割り込みを入れるメソッドである。割り込みを入れることのできるスレッドは、joinメソッドやsleepメソッドの実行により待機中のメソッド、Objectクラスのwaitメソッドで待機中のメソッドである。
 
割り込みを入れられたメソッドは、java.lang.InterruptedException例外を発生し、処理を再開する。
 

使用を推奨されないメソッド

stop()

スレッドを強制的に停止させるメソッドである。スレッドがどのような状態にあってもスレッドを停止させるため、そのスレッドが操作中のオブジェクトのデータに不整合が生じるおそれがある。
 

suspend()

スレッドを直ちに中断させるメソッドである。中断されたメソッドは次のresume()メソッドによって再開される。suspendメソッドは、スレッドが取得しているロックを解放しないため、デッドロックの原因となりやすいという問題がある。
なお、デッドロックとは、複数のスレッドがオブジェクトのロックを確保できない状態で処理が進まなくなってしまう状態のことを言う。
 

resume()

suspendメソッドによって中断されているスレッドの動作を再開するメソッドである。suspendメソッドを使用しなければ、resumeメソッドを使用することもない。
 

スレッドを停止させるには

stopメソッドは推奨されないメソッドである。それでは、スレッドを停止させるにはどうすれよいのだろうか。
スレッドが自分自身を終了させるには、実行中のrunメソッドを終了するようにしておきます。startメソッドによって新しく起動されたスレッドは、runメソッドが終了すると消滅します。
 
自分以外のスレッドを終了させるには、一般的に次のような方法を用いる。
 

  1. runメソッドを実装したクラスで、スレッドの実行状態を表現するboolean型変数を宣言する。
  2. runメソッド内で、繰り返しスレッドの実行状態を確認し、実行状態が「終了」を示す値になっていればrunメソッドが終了されるようにしておく。
  3. そのスレッド実行状態を変更するためのメソッドを宣言する。
  4. スレッド実行状態を「実行中」を示す値に設定し、新しいスレッドを起動する。
  5. 外部から、スレッド実行状態を変更するためのメソッドを呼び出す。

 

class someThread extends Thread{
  private boolean running = true;
   
  public void start(){
    new Thread(this).start();
   }
   
  public void run(){
    while(running){
      ...... //スレッドで実行したい処理
    }
  }
   
  public void stopRunning(){
    running = false;
  }
}

 
スレッドの実行状態は、runningというメンバ変数で表現している。runningの初期値はtrueとする。スレッドが起動したあと、runメソッド内のwhileループは、runnningがtrueである限り繰り返し実行される。
外部からスレッドを停止させるにはstopRunningメソッドを呼び出す。ここでrunningの値がfalseに変更されるので、runメソッド内のwhileループは、次回の条件チェックの際に繰り返し処理を終了する。ループを抜けることによってrunメソッドも終了し、スレッドは消滅する。
 
 
以上
 
 
参考
マルチスレッドプログラミング | TECHSCORE(テックスコア)

Article written by

Comments are closed, but trackbacks and pingbacks are open.