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

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


#Worker Threadパターン
workerというのは「作業者」という意味。WorkerThreadパターンでは、**ワーカースレッド**が仕事を一つずつ取りに行き、処理を行う。仕事がなかったら、ワーカスレッドは新しい仕事が届くまで待つ。Worker Threadのことを、**Background Thread**と呼ぶこともある。

次のような例を考える。ClientThreadクラスのスレッドが、Channelクラスに仕事のリクエストを出す。Channelクラスのインスタンスはワーカースレッドを5人かかえている。ワーカースレッドは、仕事のリクエストがくるのを待っている。仕事のリクエストがやってくると、ワーカスレッドは、Channelから仕事のリクエストを1個もらって処理する。処理が終わるとワーカースレッドはChannelのところに戻ってきて次のリクエストを待つ。

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

```java:Main.java
public class Main { 
    public static void main(String[] args) { 
        Channel channel = new Channel(5);   // ワーカースレッドを5個作成
        channel.startWorkers(); // ワーカースレッドをスタートさせる
        new ClientThread("Alice", channel).start();  // 仕事のリクエストを出すスレッドをスタートさせる
        new ClientThread("Bobby", channel).start(); 
        new ClientThread("Chris", channel).start(); 
    } 
}
```

```java:ClientThread.java
public class ClientThread extends Thread { 
    ...
    public void run() { 
        try { 
            for (int i = 0; true; i++) { 
                Request request = new Request(getName(), i); 
                channel.putRequest(request);  // 仕事のリクエストを出す
                Thread.sleep(random.nextInt(1000)); 
            } 
        } catch (InterruptedException e) { 
        } 
    } 
}
```

```java:Channel.java
public class Channel { 
    private static final int MAX_REQUEST = 100; 
    private final Request[] requestQueue; 
    private int tail;
    private int head;
    private int count;
 
    private final WorkerThread[] threadPool; 
 
    public Channel(int threads) { 
        this.requestQueue = new Request[MAX_REQUEST]; 
        this.head = 0; 
        this.tail = 0; 
        this.count = 0; 
 
        threadPool = new WorkerThread[threads]; 
        for (int i = 0; i < threadPool.length; i++) { 
            threadPool[i] = new WorkerThread("Worker-" + i, this); 
        } 
    }

    public void startWorkers() { 
        for (int i = 0; i < threadPool.length; i++) { 
            threadPool[i].start(); 
        } 
    }

    public synchronized void putRequest(Request request) { 
        while (count >= requestQueue.length) { 
            try { 
                wait(); 
            } catch (InterruptedException e) { 
            } 
        } 
        requestQueue[tail] = request; 
        tail = (tail + 1) % requestQueue.length; 
        count++; 
        notifyAll(); 
    }

    public synchronized Request takeRequest() { 
        while (count <= 0) { 
            try { 
                wait(); 
            } catch (InterruptedException e) { 
            } 
        } 
        Request request = requestQueue[head]; 
        head = (head + 1) % requestQueue.length; 
        count--; 
        notifyAll(); 
        return request; 
    } 
}
```

```java:WorkerThread.java
public class WorkerThread extends Thread { 
    ...
    public void run() { 
        while (true) { 
            Request request = channel.takeRequest(); // 仕事を取りに行く
            request.execute(); 
        } 
    } 
}
```

Channelクラスは仕事のリクエストの受け渡しのためにrequestQueueというフィールドを持っている。このキューにリクエストを入れるのはputRequestメソッド、取り出すのはtakeRequestメソッド。ここでは、Producer-Consumerパターンが使われている。Thread-Per-Messageパターンでは、仕事を実行するたびに新しいスレッドを起動していた。しかしWorker Threadパターンでは、**ワーカースレッドが繰り返し仕事を実行するので、新しいスレッドを起動する必要がない。**WorkerThreadが持っているフィールドは、自分が仕事のリクエストを得るためのChannelのインスタンスだけで、具体的な仕事内容は何も知らない。

##登場人物

Client役
Client役は、仕事のリクエストをRequest役として作成し、Channel役に渡す。サンプルプログラムでは、ClientThreadクラスがこの役をつとめた。

Channel役
Channel役は、Client役からRequest役を受け取り、Worker役に渡す。サンプルプログラムでは、Channelクラスがこの役をつとめた。

Worker役
Worker役はChannel役からRequest役をもらい、その仕事を実行する。仕事が終わったら、次のRequest役をもらいにいく。サンプルプログラムでは、WorkerThreadクラスがこの役をつとめた。

Request役
Request役は、仕事を表すためのもの。Request役は、その仕事を実行するのに必要な情報を保持している。サンプルプログラムでは、Requestクラスがこの役をつとめた。

##考えを広げるためのヒント
スループットの向上
Thread-Per-Messageパターンと違ってWorkerThreadパターンでは**スレッドを使いまわし、リサイクルしてスループットを上げる**ことがテーマのひとつ。

キャパシティの制御
同時に提供できるサービスの量をキャパシティと呼ぶ。Worker役の数は自由に定めることができる。サンプルプログラムでは、Channelのコンストラクタに与える引数threadsがそれにあたる。Worker役の数が多ければ、それだけ並行して仕事をすることができるが、同時期にリクエストされる仕事の数よりも多いWorker役を用意しても役に立たず消費するリソースも増えてしまう。Worker役の数は、必ずしも起動時に定めておく必要はなく、動的に変化させることもできる。Channel役はRequest役を保持している。Channel役が保持しておくことのできるRequest役の数が多いと、Client役とWorker役の処理速度のずれを埋める(緩衝する)ことができる。しかし、Request役を保持するためには大量のメモリを消費することになる。ここには、**キャパシティとリソースのトレードオフ**があることがわかる。

invocationとexecutionの分離
通常のメソッド呼び出しを行うとき、「メソッドの起動」と「メソッドの実行」は続けて行われる。**通常のメソッド呼び出しでは、起動と実行は不可分である**。しかし、**Worker ThreadパターンやThread-Per-Messageパターンは、メソッドの起動と実行を分離している**。メソッドの起動はinvocation、実行はexecutionという。**Worker ThreadパターンやThread-Per-Messageパターンは、メソッドのinvocationとexecutionを分離している**といってもよい。これにより以下のメリットが生まれる。

- 応答性の向上
executionに時間がかかても、invocationをした方は先に進んでいくことができる。

- 実行順序の制御(スケジューリング)
Request役に優先順位を設け、Channgel役がWorker役にRequest役を渡す順番を制御できる。これを要求の**スケジューリング**という。

- キャンセル可能・繰り返し実行可能
invocationしたがexecuionはキャンセルという機能が実現できる。

- 分散処理
invokeするコンピュータとexecueするコンピュータを分けやすくなる。

多態的なRequest役
たとえば、Requestクラスのサブクラスを作り、そのインスタンスをChannelに渡したとしても、WorkerThreadは問題なくそのインスタンスのexecuteをよんでくれる。これは**多態性(ポリモルフィズム)**を利用していると表現できる。仕事を実行するのに必要な情報は、Request役にすべて記述されているため、多態的なRequest役を作って仕事の種類を増やしてもChannel役やWorker役側は修正する必要がない。仕事の種類が増えても、Worker役は相変わらずRequest役のexecuteメソッドを呼ぶだけである。


---

関連
[『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)