コード型ログ(1) スレッドを止めるにはinterruptを使う

他の人が書いていたら読めるけれども、知らなければ書けない定型的なソースコードの型を集めているので気が向いたら書いていく。ダジャレが好きなので、コード型ログと呼ぶ。今回は1回目。


無限ループを持つスレッドはinterrupt()で止められるようにする。

package org.example.katalog;

public class InterruptSample {
  public static void main(String[] args) {
    Thread t = new Thread() {
      @Override
      public void run() {
        // interruptされるまで、"Hello world"を出力し続ける。
        // なお、isInterrupted()は呼ぶとフラグがクリアされてfalseになる。
        while (!isInterrupted()) {
          System.out.println("Hello world");
        }
      }
    };

    t.start();

    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    // interruptするとスレッドのisInterrupted()のフラグが立つ。
    t.interrupt();

    // interruptしてもまだスレッドが止まっているわけではない。
    // スレッドが止まるまで待つ。
    try {
      t.join();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

悪い例は制御フラグを独自につくることである。Javaのスレッドには言語組み込みでその目的のフラグが用意されているのだからそれを使う。

package org.example.katalog;

class HelloPrinter extends Thread {
  // スレッドを止めるべきかのフラグ。
  // volatileはあるスレッドで代入した値が他のスレッドでも
  // 同じものが見えることを保証するおまじない。
  volatile boolean stop = false;

  @Override
  public void run() {
    while (!stop) {
      System.out.println("Hello world");
    }
  }
}

public class InterruptBadSample {
  public static void main(String[] args) {
    HelloPrinter t = new HelloPrinter();

    t.start();

    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    t.stop = true;

    try {
      t.join();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}