『Java同時プログラミング』の4:Executorフレームワーク

8616 ワード

詳細
ExecutoreServiceでは、ライフサイクルの管理が追加されました.実行、停止、終了の3つのステータスがあります.
public class LifecycleWebServer {
    private final ExecutorService exec = Executors.newCachedThreadPool();

    public void start() throws IOException {
        ServerSocket socket = new ServerSocket(80);
        while (!exec.isShutdown()) {
            try {
                final Socket conn = socket.accept();
                exec.execute(new Runnable() {
                    public void run() {
                        handleRequest(conn);
                    }
                });
            } catch (RejectedExecutionException e) {
                if (!exec.isShutdown())
                    log("task submission rejected", e);
            }
        }
    }

    public void stop() {
        exec.shutdown();
    }

    private void log(String msg, Exception e) {
        Logger.getAnonymousLogger().log(Level.WARNING, msg, e);
    }

    void handleRequest(Socket connection) {
        Request req = readRequest(connection);
        if (isShutdownRequest(req))
            stop();
        else
            dispatchRequest(req);
    }

    interface Request {
    }

    private Request readRequest(Socket s) {
        return null;
    }

    private void dispatchRequest(Request r) {
    }

    private boolean isShutdownRequest(Request r) {
        return false;
    }
}

 
6.2.5遅延タスクとサイクルタスク
我々は通常、Timerで遅延またはサイクル実行のいくつかのタスクを管理しますが、これは安全ではありません.Timerにはいくつかの欠陥があるため、ScheduledThreadPoolExecutorを使用して代替することを考慮する必要があります.ScheduledThreadPoolExecutorによって関数を構築したり、newScheduledThreadPoolファクトリメソッドによってクラスのオブジェクトを作成したりすることができます.
 
6.3.2結果を携帯するタスクCallableとFuture
Executorが実行するタスクには、作成、コミット、開始、完了の4つのライフサイクルフェーズがあります.一部のタスクをキャンセルする場合は、Executorフレームワークでコミットされているがまだ開始していないタスクはキャンセルできますが、実行が開始されたタスクに対しては、中断に応答できる場合にのみキャンセルできます.
 
Futureは、タスクのライフサイクルを表し、完了またはキャンセルされたかどうか、およびタスクの結果を取得したり、タスクをキャンセルしたりする方法を提供します.
ExecutorServiceのすべてのsubmitメソッドは、RunnableまたはCallableをExecutorにコミットし、タスクの実行結果を取得したり、タスクをキャンセルしたりするためのFutureを取得するために使用されるFutureを返します.指定したRunnableまたはCallableに対してFutureTaskをインスタンス化することもできます.
 
6.3.5 CompletionServices:ExecutorとBlockingQueue
Executorに計算タスクのセットをコミットし、計算が完了した後に結果を得ることを望む場合は、各タスクに関連付けられたFutrueを保持し、getメソッドを繰り返し使用しながらパラメータtimeoutを0に指定して、タスクが完了したかどうかを輪訓で判断するのは煩雑です.このスキームをCompletionServiceで最適化できます.
例:CompletionServiceを使用したページレンダラーの実装:
public abstract class Renderer {
    private final ExecutorService executor;

    Renderer(ExecutorService executor) {
        this.executor = executor;
    }

    void renderPage(CharSequence source) {
        final List info = scanForImageInfo(source);
        CompletionService completionService =
                new ExecutorCompletionService(executor);
        for (final ImageInfo imageInfo : info)
            completionService.submit(new Callable() {
                public ImageData call() {
                    return imageInfo.downloadImage();
                }
            });

        renderText(source);

        try {
            for (int t = 0, n = info.size(); t < n; t++) {
                Future f = completionService.take();
                ImageData imageData = f.get();
                renderImage(imageData);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } catch (ExecutionException e) {
            throw launderThrowable(e.getCause());
        }
    }

    interface ImageData {
    }

    interface ImageInfo {
        ImageData downloadImage();
    }

    abstract void renderText(CharSequence s);

    abstract List scanForImageInfo(CharSequence s);

    abstract void renderImage(ImageData i);

}

 
6.3.7タスクに期限を設定する:
public class RenderWithTimeBudget {
    private static final Ad DEFAULT_AD = new Ad();
    private static final long TIME_BUDGET = 1000;
    private static final ExecutorService exec = Executors.newCachedThreadPool();

    Page renderPageWithAd() throws InterruptedException {
        long endNanos = System.nanoTime() + TIME_BUDGET;
        Future f = exec.submit(new FetchAdTask());
        // Render the page while waiting for the ad
        Page page = renderPageBody();
        Ad ad;
        try {
            // Only wait for the remaining time budget
            long timeLeft = endNanos - System.nanoTime();
            ad = f.get(timeLeft, NANOSECONDS);
        } catch (ExecutionException e) {
            ad = DEFAULT_AD;
        } catch (TimeoutException e) {
            ad = DEFAULT_AD;
            f.cancel(true);
        }
        page.setAd(ad);
        return page;
    }

    Page renderPageBody() {
        return new Page();
    }


    static class Ad {
    }

    static class Page {
        public void setAd(Ad ad) {
        }
    }

    static class FetchAdTask implements Callable {
        public Ad call() {
            return new Ad();
        }
    }

}

 
6.3.8もう一つ使いやすいinvokeAll方法があります
期間限定のinvokeAllをサポートし、複数のタスクを1つのExecutorServiceにコミットして結果を得る.invokeAllメソッドパラメータは、タスクのセットであり、Futureのセットを返します.この2つの集合は同じ構造を持っている.invokeAllは、タスクセット内の反復器の順序ですべてのFutureを戻りセットに追加し、呼び出し元が各Futureを表すCallableに関連付けることができるようにします.したがって、タスクが完了すると、呼び出しスレッドが中断したり、タイムアウトしたりすると、invokeAllが返されます.指定した期限を超えると、未完了のタスクはキャンセルされます.
時間限定見積サービスで説明します.
public class TimeBudget {
    private static ExecutorService exec = Executors.newCachedThreadPool();

    public List getRankedTravelQuotes(TravelInfo travelInfo, Set companies, Comparator ranking, long time, TimeUnit unit)
            throws InterruptedException {
        List tasks = new ArrayList();
        for (TravelCompany company : companies)
            tasks.add(new QuoteTask(company, travelInfo));

        List> futures = exec.invokeAll(tasks, time, unit);

        List quotes = new ArrayList(tasks.size());
        Iterator taskIter = tasks.iterator();
        for (Future f : futures) {
            QuoteTask task = taskIter.next();
            try {
                quotes.add(f.get());
            } catch (ExecutionException e) {
                quotes.add(task.getFailureQuote(e.getCause()));
            } catch (CancellationException e) {
                quotes.add(task.getTimeoutQuote(e));
            }
        }

        Collections.sort(quotes, ranking);
        return quotes;
    }

}

class QuoteTask implements Callable {
    private final TravelCompany company;
    private final TravelInfo travelInfo;

    public QuoteTask(TravelCompany company, TravelInfo travelInfo) {
        this.company = company;
        this.travelInfo = travelInfo;
    }

    TravelQuote getFailureQuote(Throwable t) {
        return null;
    }

    TravelQuote getTimeoutQuote(CancellationException e) {
        return null;
    }

    public TravelQuote call() throws Exception {
        return company.solicitQuote(travelInfo);
    }
}

interface TravelCompany {
    TravelQuote solicitQuote(TravelInfo travelInfo) throws Exception;
}

interface TravelQuote {
}

interface TravelInfo {
}

 
私のブログはすでに引っ越して、新しい住所は:http://yidao620c.github.io/