『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その１２)

<img width="300" alt="javathread.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/165994/9d302410-0471-96c1-f097-d46649d17209.jpeg">


#Two-Phase Terminationパターン

ポイントは、
- 安全に終了すること(安全性)
- 必ず終了処理を行うこと(生存性)
- 終了処理を出したらできるだけ早く終了処理に入ること(応答性)

約500ミリ秒間隔でカウントアップを行っているスレッドを、約10秒後に終了させるというプログラムを考える。

(コード全体は本書を参照のこと)

```java:Main.java
public class Main { 
    public static void main(String[] args) { 
        try { 
            CountupThread t = new CountupThread(); 
            t.start(); 
            Thread.sleep(10000); 
            t.shutdownRequest(); 
            t.join(); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } 
    } 
}
```

```java:CountupThread.java
public class CountupThread extends Thread { 
    private long counter = 0; 
    private volatile boolean shutdownRequested = false; 
 
    public void shutdownRequest() { 
        shutdownRequested = true; 
        interrupt(); 
    } 
 
    ... 

    public final void run() { 
        try { 
            while (!isShutdownRequested()) { 
                doWork(); 
            } 
        } catch (InterruptedException e) { 
        } finally { 
            doShutdown(); 
        } 
    } 
 
    private void doWork() throws InterruptedException { 
        counter++; 
        System.out.println("doWork: counter = " + counter); 
        Thread.sleep(500); 
    } 
 
    ... 
}
```

##登場人物
TerminationRequester役
TerminationRequester役は、Terminator役へ終了要求を出す。サンプルプログラムでは、Mainクラスがこの役をつとめた。

Terminator役
Terminator役は、終了要求を受けて、実際に終了処理を行う。Terminator役は、終了要求を表すshutdownRequestメソッドを提供する。Terminator役は、自分が終了要求を受けたかどうかを表すフラグ(ラッチ)を持っている。サンプルプログラムでは、CountupThreadクラスがこの役をつとめた。

##考えるを広げるヒント
Threadクラスのstopメソッドを使ってはいけない
stopを使うと、クリティカルセクションの実行途中であっても、スレッドはjava.lang.ThreadDeathという例外を投げて終了する。

フラグのテストだけでは不十分
shutdownRequestメソッドの中で、**interruptメソッド**を呼ぶ必要があるか。shutdownRequestフラグだけではだめか。shutdownRequestedフラグだけだと、例えばスレッドがsleepしていたら、いくらフラグをtrueにしても終了処理を始めてくれない。sleep時間が過ぎれば終了処理を始めてくれるかもしれないが、それでは応答性が悪くなってしまう。interruptメソッドを使えば、sleepやwaitを中断することができる。

インタラプト状態のテストだけでも不十分
今度は逆に、interruptメソッドを呼ぶだけではだめか。例えば、スレッドが実行しているdoWorkメソッドの中で次のように記述してしまうとうまくいかない。

```java
    private void doWork() throws InterruptedException { 
        counter++; 
        System.out.println("doWork: counter = " + counter);
        try { 
            Thread.sleep(500);
        } catch (InterruptedException e) {
        } 
    }
```


interruptメソッドについて
**interruptメソッドを呼び出すと、対象のスレッドは常にInterruptedExceptionを投げると思っているかもしれないが、それは誤解である。interruptというメソッドは、スレッドのインタラプト状態を変えるだけである。インタラプト状態とは、スレッドがインタラプトされているかどうかを表している状態のこと。sleep, wait, joinがInterruptedExcpetionを投げるのは、それらがメソッドの内部でスレッドのインタラプト状態を調べ、明示的にInterruptedExceptionを投げているからである。wait, sleep, joinでいったんInterruptedExceptionが投げられると、スレッドはインタラプト状態ではなくなる。**

---

関連
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その１)](http://qiita.com/yoshi-yoshi/items/83ecc4476904fa144577)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その２)](http://qiita.com/yoshi-yoshi/items/792ed2e9dc09f63c5004#_reference-5f26b880e1c02b87a1d8)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その３)](http://qiita.com/yoshi-yoshi/items/1d2c0e1279af4adb2e9b)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その４)](http://qiita.com/yoshi-yoshi/items/3b642f91b27120cc4b15)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その５)](http://qiita.com/yoshi-yoshi/items/427be45a8b0044083911)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その６)](http://qiita.com/yoshi-yoshi/items/38187c25619a173ea8b8)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その７)](http://qiita.com/yoshi-yoshi/items/1b6f4e0247496fdaac4c)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その８)](http://qiita.com/yoshi-yoshi/items/eefbf9ee8137f7ba808d)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その９)](http://qiita.com/yoshi-yoshi/items/2e1ba112266a10645151)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その１０)](http://qiita.com/yoshi-yoshi/items/06294f81756a1c07f414)
[『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その１１)](http://qiita.com/yoshi-yoshi/items/d81a6bb4c83f5b31c991)