マルチスレッドプログラミングのFutureパターン

By | 2011年7月15日

マルチスレッドプログラミングのパターンの一つにFutureパターンというものがある。
これは、ある処理を別スレッドで非同期に実行させて、その結果を受けたいときに用いられるパターンである。
特徴的なのは、処理の実行担当者(JavaではExecutorServiceがそれにあたる)は、処理(JavaではCallable)が渡されると別スレッド上で処理を開始して、メインスレッドには即座にFutureオブジェクトを返すことである。
なぜこのオブジェクトがFutureと呼ばれるかというと、今現在はまだ結果を取得できないが、将来のある時点で取得することになるからである。
その後、Futureのget()メソッドを呼ぶと、メインスレッドはCallableの処理が終わるまでブロックされる。
そして別スレッドで処理が終わった時点で結果が取得できる。

プログラム例を以下に示す。

public static void main(String[] args) {

	ExecutorService es = Executors.newSingleThreadExecutor();

	// submit()は、別スレッド上でCallableの処理を開始し、
	// メインスレッドには即座にFutureオブジェクトを返す
	Future<String> future = es.submit(new Callable<String>() {

		// 別スレッドで実行する処理
		@Override
		public String call() throws Exception {
			System.out.println("Callable start");

			// ・・・何らかの重い処理。
			// 5秒待つ
			Thread.sleep(5000);

			return "result ok.";
		}

	});

	System.out.println("Callable submit.");

	String result = "";
	try {
		// Callableの処理が終わり、結果が返ってくるまでブロックされる。
		result = future.get();
	} catch (InterruptedException e) {
		e.printStackTrace();
	} catch (ExecutionException e) {
		e.printStackTrace();
	}

	System.out.println("result=" + result);
}

このプログラムを実行すると

Callable submit. ・・・①
Callable start ・・・ ②
result=result ok. ・・・ ③

と表示される。
最初に①と②が表示された後、5秒後に③が表示される。
もしかすると、①と②の表示順番は逆転するかも知れない。

ちなみに、C#で同じ事をやろうとすると以下のようになるのではないかと思う。

delegate String DoAsync();

private void button1_Click(object sender, EventArgs e)
{
    DoAsync da = () =>
    {
        Console.WriteLine("async method start.");

        System.Threading.Thread.Sleep(5000);
        return "result ok.";
    };

    IAsyncResult ar = da.BeginInvoke(null, null);
    Console.WriteLine("BeginInvoke called.");

    String result = da.EndInvoke(ar);
    Console.WriteLine(result);
}

実行すると、始めに

BeginInvoke called.
async method start.

と表示された後、5秒後に

result ok.

と表示されるだろう。

C#の場合はデリゲートを非同期で実行できるので、多少すっきりと書くことが出来る。ただし、このやり方だと必ず標準のスレッドプールで実行される。
対して、Javaの場合はExecutors#newSingleThreadExecutor()の引数にThreadFactoryを渡せばスレッド作成の仕方をコントロールできる分、柔軟性があるとも言えると思う。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です