multi thread 9

Future (先物)パターン

返り値を得るまで時間のかかる処理をFutureパターンで実装すると,依頼したクラスは直ちに「FutureData」を返り値として受け取る.これは受け取った時点では値がないが,しばらくして処理が終わったころにアクセスしてみると,実際のデータ「RealData」が返ってくるようなものである.いわば,引換券のようなもの.

  • Host class
    public class Host {
        public Data request(args) {
            // (1) create a new FutureData
            final FutureData future = new FutureData();
            // (2) Invocation for creating a new RealData
            new Thread() {
                public void run() {
                    RealData realdata = new RealData(args);
                    future.setRealData(realdata);
                }
            }.start();
            // (3) return the instance of FutureData
            return future;
        }
    
    }
    1. FutureDataのインスタンスを作る
      リクエストを受け取ると作り始める
    2. RealDataのインスタンスを作るための新しいスレッドを起動する
      新しいスレッドの中でRealDataのインスタンスを作るようにする
    3. FutureDataのインスタンスを戻り値とする
      リクエストを呼び出した(メイン)スレッドはfutureを戻り値として直ちに帰る.
  • Data IF
    抽象メソッド getContent() を表現したインターフェース.FutureDataとRealDataが実装する
  • FutureData class
    引換券となるクラス.readyはrealdetaに値が代入されたかどうかを表すフィールド.
    setRealDataではRealDataのインスタンスをrealdataに代入する.RealDataのインスタンスができたら,readyをtrueにし,getContentの中で待っているスレッドを起こすためにnotifyAllする.一方,2回以上RealDataのインスタンスを生成するのはリソースの無駄なのでBalkingパターンでこれを防いでいる.
    getContentは実際のデータを得るためのメソッド.readyをガード条件としてGuarded Suspensionパターンでrealdataがセットされるのを待っている.

    public class FutureData implements Data {
        private RealData realdata = null;
        private boolean ready = false;
        public synchronized void setRealData(RealData realdata) {
            if (ready) {
                return;
            }
            this.realdata = realdata;
            this.ready = true;
            notifyAll();
        }
        public synchronized String getContent() {
            while (!ready) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
            return realdata.getContent();
        }
    }
  • RealData class
    RealDataクラスはインスタンスを作るのに時間がかかるクラス.このクラスには「インスタンスができるまで待つ」というようなスレッド制御は含まれていない.マルチスレッドのことは何も考えなくて良い.

    public class RealData implements Data {
        private final String content;
        public RealData (args) {
            (consume a lot of time)
        }
        public String getContent() {
            return content;
        }
    }

Futureはコールバックよりもマルチスレッドにおいて安全.
コールバックというのは,処理が完了したときにHost役(新規スレッドを作り起動する)が起動したスレッドがClient役(タスクを依頼した)のメソッドを呼ぶ.ただし,マルチスレッドではこのClient役の方でもマルチスレッドを意識しないといけない.

java.util.concurrentパッケージに含まれているクラスとインターフェースも見ておくと

  • java.util.concurrent.Callable IF
    戻り値のある処理の呼び出しを抽象化している.callメソッドが宣言されている.Callable<String> は「callメソッドの戻り値の型がStringであるCallableIF」を表す
  • java.util.concurrent.Future IF
    Futureを抽象化している.値を取得するget, 実行を中断するcancelが宣言されている.値をセットするセッターメソッドは実装クラスで実装する必要がある.
  • java.util.concurrent.FutureTask Class
    FutureIFを実装した標準的なクラス.値を設定するset,例外を設定するsetExceptionメソッドが宣言されている.また,FutureTaskはRunnableIFも実装しているので,runメソッドも実装されている.

CallableIFを使うと,Host Classは

public class Host {
    public Data request(args) {
        // (1) create a new FutureData
        final FutureData future = new FutureData(
            new Callable<RealData>() {
                public RealData call() {
                    return new RealData(args);
                }
            }
        );
        // (2) Invocation for creating a new RealData
        new Thread(future).start();
        // (3) return the instance of FutureData
        return future;
    }

}

次に,FutureTaskを使うと,FutureDataクラスは

public class FutureData extends FutureTask<RealData> implements Data {
    public FutureData(Callable<RealData> callable) {
        super(callable);
    }
    public String getContent() {
        String string = null;
        try {
            string = get().getContent();  // (1)
        } catch (InterruptedException e) {
        } catch (ExecutionException e) {
        }
        return string; // (2)
    }
}

コンストラクタで与えられたCallableオブジェクトは,そのままスーパークラスのFutureTaskに渡す.callメソッドの呼び出しはFutureTaskクラスにお任せする.get()はFutureTaskのメソッドで戻り値はFutureTask<RealData>としたので,RealDataが返ってくる.なので,getContent()することができ(1),これをDataの実装としてgetContent()の返り値(2)としている.

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中