--/--/--

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

2008/01/13

Executor フレームワーク

Java 5 で追加された Executor フレームワーク(java.util.concurrent パッケージ)。タスクと実行ポリシーを分割する Executor インタフェースを中心とする、並列処理プログラミングのフレームワークである。今日はその練習として、並列クイックソートを書いた。

ただし、激遅。まぁこんだけ new ArrayList して add して remove してを繰り返せば遅くなる罠。

public class PararellSorter {

    class SortTask<E extends Comparable<E>> implements Callable<List<E>> {

        final List<E> list;

        SortTask(List<E> list) {
            this.list = list;
        }

        public List<E> call() throws Exception {
            if (list.isEmpty()) {
                return list;
            }
            E mid = list.get(0);
            list.remove(mid);
            Future<List<E>> lt = submitLT(mid);
            Future<List<E>> gteq = submitGTEQ(mid);
            List<E> ret = lt.get();
            ret.add(mid);
            ret.addAll(gteq.get());
            return ret;
        }

        private Future<List<E>> submitLT(E mid) {
            List<E> ret = new ArrayList<E>();
            for (E value : list) {
                if (value.compareTo(mid) == -1) {
                    ret.add(value);
                }
            }
            return exec.submit(new SortTask<E>(ret));
        }

        private Future<List<E>> submitGTEQ(E mid) {
            List<E> ret = new ArrayList<E>();
            for (E value : list) {
                if (value.compareTo(mid) >= 0) {
                    ret.add(value);
                }
            }
            return exec.submit(new SortTask<E>(ret));
        }
    }

    private final ExecutorService exec;

    public PararellSorter(ExecutorService exec) {
        this.exec = exec;
    }

    public PararellSorter() {
        this(Executors.newCachedThreadPool());
    }

    public <E extends Comparable<E>> List<E> sort(List<E> target) throws InterruptedException {
        Future<List<E>> task = exec.submit(new SortTask<E>(target));
        try {
            return task.get();
        } catch (ExecutionException e) {
            task.cancel(true);
            throw handleExecutionException(e.getCause());
        } catch (InterruptedException e) {
            task.cancel(true);
            throw e;
        }
    }

    private void doSample() throws Exception {
        List<Integer> l = makeRandomArray();
        try {
            long pstart = System.currentTimeMillis();
            sort(l);
            long pend = System.currentTimeMillis();
            System.out.println("TIME: " + (pend - pstart));
        } finally {
            exec.shutdownNow();
            exec.awaitTermination(10, TimeUnit.SECONDS);
        }
    }

    public static void main(String[] args) throws Exception {
        new PararellSorter().doSample();
    }

}

import 文と一部のヘルパーメソッドとは省略してます。

ExecutorService と Future はかなり便利。

  • キャンセル・シャットダウンが楽ちん
  • 例外処理がしやすい(投げられる例外が原因によってちゃんと分けられてる)

Executor が中心なのに、Executor 出てきてないじゃん!と思いの方へ。

Executor インタフェースは、自身のライフサイクル管理には全く気を配っていません。その機能拡張を施した、ExecutorService という Executor を継承したインタフェースがあります。

標準 API で用意されている Executor のファクトリメソッドの戻り値は、ExecutorService を実装したクラスのインスタンスのみとなっています。実際に使うのも ExecutorService が多いです。なので、Executor は直接ソースコードに出てきていないのです。

スポンサーサイト

comment

post




上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。