西海岸より

つらつらざつざつと

スレッド終了のお作法

マルチスレッドのプログラムはまともに書いたことが無く、迷ったのが実行し続けるスレッドの終了方法。

  • LoopThreadTest.java(最初の実装)
public class LoopThreadTest{
        public static void main(String[] args){
                System.out.println("LoopThreadTest: start");
                LoopThread thread = new LoopThread();
                thread.setDaemon(true);

                //start LoopThread
                thread.start();

                try{
                        Thread.sleep(4000);
                }catch(InterruptedException e){
                        //nop
                }

                //term LoopThread
                thread.notifyStop();
                thread.interrupt();

                //wait
                try{
                        thread.join(1000);
                }catch(InterruptedException e){
                        //nop
                }
                System.out.println("LoopThreadTest: end");
        }
}

class LoopThread extends Thread{
        private boolean loopFlag = true;
        public void notifyStop(){
                loopFlag = false;
        }
        public void run(){
                System.out.println("LoopThread#run: start");
                int loopCount = 0;
                while(loopFlag){
                        System.out.println("LoopCount: " + loopCount);
                        try{
                                sleep(1000);
                        }catch(InterruptedException e){
                                System.out.println("LoopThread#run: " +
                                        e.getMessage());
                        }
                        loopCount++;
                }
                System.out.println("LoopThread#run: end");
        }
}
  • 実行結果
mmasashi-macbook:threadtest mmasashi$ java LoopThreadTest
LoopThreadTest: start
LoopThread#run: start
LoopCount: 0
LoopCount: 1
LoopCount: 2
LoopCount: 3
LoopThread#run: sleep interrupted
LoopThread#run: end
LoopThreadTest: end

ここで久々に結城さんの本で確認。

interruptメソッドの特徴としては、

    • thread.interrupt()は、threadの状態を割り込み状態にする
    • threadがsleep, join, wait(InterruptedExceptionをスローするメソッド)を実行中にthread.interrupt()を実行した場合、threadの状態は変更されず、InterruptedExceptionがスローされる

これより、LoopThread#runのwhile文の中で、interruptが実行されるタイミングがsleep以外の場合はスレッドの状態が割り込みかどうかで判断し、sleep中の場合にはInterruptedExceptionをキャッチした中でbreakしてループを抜けるという実装で、インスタンス変数も減ってシンプルになるはず。

  • LoopThreadTest.java (修正後)
public class LoopThreadTest{
        public static void main(String[] args){
                System.out.println("LoopThreadTest: start");
                LoopThread thread = new LoopThread();
                thread.setDaemon(true);

                //start LoopThread
                thread.start();

                try{
                        Thread.sleep(4000);
                }catch(InterruptedException e){
                        //nop
                }

                //term LoopThread
                thread.interrupt();

                //wait
                try{
                        thread.join(1000);
                }catch(InterruptedException e){
                        //nop
                }
                System.out.println("LoopThreadTest: end");
        }
}

class LoopThread extends Thread{
        public void run(){
                System.out.println("LoopThread#run: start");
                int loopCount = 0;
                while(!isInterrupted()){
                        System.out.println("LoopCount: " + loopCount);
                        try{
                                sleep(1000);
                        }catch(InterruptedException e){
                                System.out.println("LoopThread#run: " +
                                        e.getMessage());
                                break;
                        }
                        loopCount++;
                }
                System.out.println("LoopThread#run: end");
        }
}

関係ないけどJava APIのドキュメントで誤字発見。

    isInterrupted()
     このスレッドが割り込まれているどうかを調べます。

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―