Javaでスレッドを安全に終了する方法|volatileフラグを使った実装例
Javaでは、実行中のスレッドを外部から強制的に即座に停止させる安全な手段は用意されていません。かつて提供されていた Thread.stop() メソッドは、スレッドが保持しているロックやデータの整合性を壊す恐れがあるため、現在では非推奨(deprecated)となっています。
そこで推奨されるのが、volatile 修飾子を付けた boolean 型のフラグを使い、スレッド自身に終了タイミングを判断させる方法です。以下に具体的な実装例を示します。
コード例
public class Main{
static volatile boolean exit = false;
public static void main(String[] args){
System.out.println("Starting the main thread");
new Thread(){
public void run(){
System.out.println("Starting the inner thread");
while (!exit){
}
System.out.println("Exiting the inner thread");
}
}.start();
try{
Thread.sleep(100);
}
catch (InterruptedException e){
System.out.println("Exception caught :" + e);
}
exit = true;
System.out.println("Exiting main thread");
}
}
実行結果
Starting the main thread Starting the inner thread Exiting main thread Exiting the inner thread
コードの解説
まず、メインクラス内で新しいスレッドを作成し、その run() メソッドを呼び出しています。ここで定義されている exit は boolean 型の変数で、初期値は false です。volatile 修飾子が付いているため、この変数への変更は複数スレッド間で確実に可視化され、キャッシュされた古い値を読み続ける問題を防げます。
無限ループ(while (!exit))を持つ内部スレッドは、start() メソッドによって起動されます。一方、メインスレッドでは try ブロック内の Thread.sleep(100) によって100ミリ秒間待機し、この間に割り込みが発生した場合は catch ブロックで例外を捕捉してメッセージを表示します。
待機時間が経過すると、メインスレッドは exit の値を true に設定します。これにより内部スレッドの while ループ条件が成立しなくなり、ループを抜けてスレッドが自然な形で終了します。最後にメインスレッドも終了し、プログラム全体が完了します。
ポイントまとめ
volatileを付けることで、フラグの変更がすべてのスレッドから即座に参照できるようになるThread.stop()は非推奨。デッドロックやデータ破損の原因となるため使用しない- スレッドは外部から強制終了させるのではなく、フラグを見て自ら終了する設計がベストプラクティス
-
JavaでRunnableインターフェースを明示的に実装せずにスレッドを作成する方法
スレッドは軽量プロセス(ライトウェイト・プロセス)と呼ばれることがあります。Javaはマルチスレッドを標準でサポートしており、アプリケーション内で2つ以上のタスクを同時に実行できます。すべてのJavaプログラムには、少なくとも1つのメインスレッドが存在します。このメインスレッドは、プログラムの起動時にJava Virtual Machine(JVM)によって作成され、その上でmain()メソッドが実行されます。Javaでスレッドを作成する一般的な方法としては、次の2つが知られています。Threadクラスを継承するRunnableインターフェースを実装したクラスを定義するしかし、専用のクラスを宣
-
Javaで匿名クラスを使ってスレッドを作成する方法
スレッド(Thread)とは、プログラムの他の部分と同時に実行できる処理単位のことです。すべてのJavaプログラムには、少なくとも1つの「メインスレッド」が存在します。このメインスレッドは、Java仮想マシン(JVM)がプログラムの起動時にmain()メソッドを呼び出す際に自動的に作成されるものです。Javaでスレッドを作成する一般的な方法としては、Threadクラスを継承する方法と、Runnableインターフェースを実装する方法の2つがあります。さらに、以下のサンプルコードのように、Threadクラスを明示的に継承したクラスを定義しなくても、匿名クラス(無名クラス)を利用すればその場でスレッ