HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

Threadはinterruptすれば停止するというものではないのだよ

何か処理をしているThreadがあるとき、その処理を停止させるときに一番多いケースはThread#interrupt()メソッドを呼ぶことだろうか。
しかし、interrupt()メソッドを呼べばどんなスレッドでも停止するというわけではない。

そもそも停止できない

public class Main1 {

    private static class HogeThread1 extends Thread {
        public void run() {
            while (true) {
                System.out.println("running");
            }
        }
    }

    public static void main(String[] args) {
        Thread th = new HogeThread1();
        th.start();
        th.interrupt();
    }

}

極端な例ではあるが、ループの中にinterrupt()メソッドの介入を受ける処理が存在しないため、ループから抜けることはない。よってスレッドが停止することはない。

InterruptedExceptionを無視している

public class Main2 {

    private static class HogeThread2 extends Thread {
        public void run() {
            while (true) {
                System.out.println("begin of loop");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    System.out.println("interrupted");
                    e.printStackTrace(System.out);
                }
                System.out.println("end of loop");
            }
        }
    }

    public static void main(String[] args) {
        Thread th = new HogeThread2();
        th.start();
        th.interrupt();
    }

}

Thread#sleep()メソッドの呼び出しという、interrupt()メソッドの介入を受ける処理が存在するが、interrupt()メソッドが呼ばれたときに発生するInterruptedExceptionを(ログを出力するだけで)無視している。そのため、スレッドが停止することはない。

停止方法が間違っている

import java.util.ArrayList;
import java.util.List;

public class Main3 {

    private static class HogeThread3<T> extends Thread {
        private List<T> list;
        public HogeThread3(List<T> list) {
            this.list = list;
        }
        public void run() {
            while (true) {
                System.out.println("begin of loop");
                try {
                    synchronized (list) {
                        list.wait();
                        if (list.size() == 0) {
                            break;
                        }
                        list.remove(0);
                    }
                } catch (InterruptedException e) {
                    System.out.println("interrupted");
                    e.printStackTrace(System.out);
                }
                System.out.println("end of loop");
            }
        }
    }

    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        HogeThread3<String> th = new HogeThread3<String>(list);
        th.start();
        th.interrupt();
    }

}

ちょっと複雑な例だが、キューのconsumer(消費者)としての処理を別スレッドで行うという場合に見られる例(だいぶ手抜きだけど‥)。
「list.wait()」というコードがあるので、wait中にlistが空の状態で「list.notify()」が呼ばれればループを抜ける。しかし、正しい手順を踏んでいないし、InterruptedExceptionを無視しているのでループを抜けない。