読者です 読者をやめる 読者になる 読者になる

JavaのThread.interruptを試す

JavaのThread.interruptを試してみたメモです。

JavaのThread.interruptの挙動をsleep(),wait(),join(),自作のメソッドで確認してみました。

Thread.interrupt()

interrupt()はThreadクラスのメソッドで、そのスレッドへ割り込みを行います。
sleep(),wait(),join()でinterrupt()が実行されると、InterruptedExceptionが発生します。

interrupt()の実行で必ずInterruptedExceptionが発生するわけではなく、
interrupt()によってそのスレッドの割り込みステータスがtrueとなります。
trueとなっている場合にどのような処理を行うかはそのメソッドの実装によって異なり、
sleep(),wait(),join()の場合はInterruptedExceptionを投げる実装になっています。

Thread.isInterrupted()

Thread.isInterrupted()でそのスレッドの割込みステータスの状態を返します。

sleep()でのinterrupt

sleep()実行中にinterrupt()を実行してみます。
sleep()を行うスレッドを生成、実行し、そのスレッドに対してinterrupt()を実行しています。

SleepInterruptMain.java

public class SleepInterruptMain {
    public static void main(String[] args) throws InterruptedException {

        Thread sleepThread = new Thread(new SleepTask());
        sleepThread.start();

        System.out.println(sleepThread.getName() + " isInterrupted: " + sleepThread.isInterrupted());

        Thread.sleep(1_000);
        sleepThread.interrupt();

        System.out.println(sleepThread.getName() + " isInterrupted: " + sleepThread.isInterrupted());
    }

    public static class SleepTask implements Runnable {
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + " sleep start.");
                Thread.sleep(10_000);
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + " Interrupt!");
            }
        }
    }
}

実行してみると、sleep()が中断されました。
isInterruptedを見てみると、実行後にtrueになっていることが分かります。

Thread-0 isInterrupted: false
Thread-0 sleep start.
Thread-0 isInterrupted: true
Thread-0 Interrupt!

2回めのisInterruptedですが、タイミングによってはfalseになる場合があります。
これは、sleep(),wait(),join()でInterruptedExceptionが発生した場合に割り込みステータスがリセットされるためで、
interrupt()された直後にisInterrupted()でチェックされないとtrueにならず、リセットされてしまっている場合があります。

wait()でのinterrupt

これもsleep()と同様に試してみます。
wait()実行中にinterrupt()を実行してみます。
wait()を行うスレッドを生成、実行し、そのスレッドに対してinterrupt()を実行しています。

WaitInterruptMain.java

public class WaitInterruptMain {
    public static void main(String[] args) throws InterruptedException {

        Thread waitThread = new Thread(new WaitTask());
        waitThread.start();

        System.out.println(waitThread.getName() + " isInterrupted: " + waitThread.isInterrupted());

        Thread.sleep(1_000);
        waitThread.interrupt();

        System.out.println(waitThread.getName() + " isInterrupted: " + waitThread.isInterrupted());
    }

    public static class WaitTask implements Runnable {
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + " wait.");
                doWait();
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + " Interrupt!");
            }
        }

        private synchronized void doWait() throws InterruptedException {
            wait();
        }
    }
}

実行してみると、wait()が中断されました。
isInterruptedを見てみると、実行後にtrueになっていることが分かります。

Thread-0 isInterrupted: false
Thread-0 wait.
Thread-0 isInterrupted: true
Thread-0 Interrupt!
join()でのinterrupt

これもsleep()と同様に試してみます。
join()実行中にinterrupt()を実行してみます。
join()を行うスレッドを生成、実行し、そのスレッドに対してinterrupt()を実行しています。

JoinInterruptMain.java

public class JoinInterruptMain {
    public static void main(String[] args) throws InterruptedException {

        Thread joinThread  = new Thread(new JoinTask());
        joinThread.start();

        System.out.println(joinThread.getName() + " isInterrupted: " + joinThread.isInterrupted());

        Thread.sleep(1_000);
        joinThread.join(1_000);
        joinThread.interrupt();

        System.out.println(joinThread.getName() + " isInterrupted: " + joinThread.isInterrupted());
    }

    public static class JoinTask implements Runnable {
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + " join task start.");
                Thread.sleep(10_000);
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + " Interrupt!");
            }
        }
    }
}

実行してみると、join()が中断されました。
isInterruptedを見てみると、実行後にtrueになっていることが分かります。

Thread-0 isInterrupted: false
Thread-0 join task start.
Thread-0 isInterrupted: true
Thread-0 Interrupt!

myMethod()でのinterrupt

自分で定義したmyMethod()実行中にinterrupt()を実行してみます。
myMethod()実行中にinterrupt()を実行しても、InterruptedExceptionは発生しません。
InterruptedExceptionをthrowする処理を行ってないためです。
myMethod()の中でisInterrupted()で割込みステータスの状態を確認し、割り込みされている場合returnするようにしています。

MyMethodInterruptMain.java

public class MyMethodInterruptMain {
    public static void main(String[] args) throws InterruptedException {

        Thread myThread = new Thread(new MyTask());
        myThread.start();

        System.out.println(myThread.getName() + " isInterrupted: " + myThread.isInterrupted());

        Thread.sleep(1_000);
        myThread.interrupt();

        System.out.println(myThread.getName() + " isInterrupted: " + myThread.isInterrupted());
    }

    public static class MyTask implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " MyTask start.");
            myMethod();
        }
    }

    public static void myMethod() {
        while (true) {
            if (Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName() + " Interrupt!");
                return;
            }
        }
    }
}

実行してみると、myThread()が中断されました。
特にInterruptedExceptionは発生していません。
isInterruptedを見てみると、実行後にtrueになっていることが分かります。

Thread-0 isInterrupted: false
Thread-0 MyTask start.
Thread-0 isInterrupted: true
Thread-0 Interrupt!

サンプルコードは下記にあげました。

github.com

終わり。


【参考】