Java Concurrency 之 Executor Framework

1. Executor接口

public interface Executor {
void execute(Runnable command);
}

2. 線程池

Executors的工廠方法可以返回多種線程池:

i. newFixedThreadPool(int nThread),固定大小的線程池,一直維持nThread個線程;

ii. newCachedThreadPool(),根據負載,自動調整線程池線程個數;

iii. newSingleThreadExecutor(),單線程的Executor;

iv. newScheduledThreadPool(int nThread),固定大小的線程池,可以延遲和週期性的執行任務,類似於Timer()(java1.5之後就應該很少用它了);

 

3. 具有生命週期的executor

ExecutorService一般爲執行一組任務,它在沒有shutdown前會一直等待。

awaitTermination會阻塞當前調用線程,等待線程池中的線程執行完成,或者超時,注意之前必須先調用shutdown。

public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
// ... additional convenience methods for task submission
}

4. Callable和Future

Executor的基本執行單元是Runner,但Runner不能返回值,也不好取消等。

接口Callable可以返回計算的值:

public interface Callable<V> {
V call() throws Exception;
}

 而Future則可以管理任務的生命週期:

public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException,
CancellationException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException,
CancellationException, TimeoutException;
} 

ExecutorService.submit()方法會返回一個Future,可以用來獲取返回值,或者取消任務。

也可以實例化FutureTask。

5. CompletionService,BlockingQueue和Executor的組合

你可以提交(submit)一組Callable任務,且像隊列一樣在可用時獲取(poll或者taken)計算結果,結果都被包裝在Future裏。

引用書上的例子:

瀏覽器渲染HTML頁面,先從HTML中獲取圖片的地址,加入到任務隊列中,然後渲染文字,圖片到了後,就立即顯示。

 

package org.jamie.demo;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

class ImageData {
    private final String data;

    public String getData() {
        return data;
    }

    public ImageData(String data) {
        super();
        this.data = data;
    }
}

class ImageLoader {
    private Random ran = new Random();

    public ImageData load(String src) throws InterruptedException {
        long loadTime = 0L;
        do {loadTime = ran.nextInt(10000);} //load time between 1 secs and 10 secs.
        while (1000 > loadTime);

        Thread.sleep(loadTime);
        return new ImageData("image data for " + src);
    }
    
}

public class ExecutorServiceDemo {
    private ImageLoader imageLoader = new ImageLoader();

    public void renderHtmlPage() throws Throwable {
        ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
        List<String> imagesSources = scanImageSources();
        CompletionService<ImageData> cs = new ExecutorCompletionService<ImageData>(executor);
        for (final String src : imagesSources) {
            cs.submit(new Callable<ImageData> () {
                @Override
                public ImageData call() throws Exception {
                    return imageLoader.load(src);
                }
                
            });
        }
        randerText();

        for (int i = 0; i < imagesSources.size(); ++i) {
            try {
                Future<ImageData> future = cs.poll(2, TimeUnit.SECONDS);
                if (null != future) {
                    ImageData data = future.get();
                    randerImage(data);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (ExecutionException e) {
                throw e.getCause();
            }
        }
        executor.shutdown();
    }

    private void randerImage(ImageData data) {
        System.out.println("image of HTML " + data.getData());
    }

    private void randerText() {
        System.out.println("text content of HTML");
    }

    private List<String> scanImageSources() {
        return Arrays.asList(
                "/foo.png",
                "/bar.png",
                "/beauty.jpg",
                "/food.png",
                "/sex.png",
                "/ml.png",
                "/boring.png");
    }

    public static void main(String[] args) throws Throwable {
        new ExecutorServiceDemo().renderHtmlPage();
    }
}

  輸出:

 寫道
text content of HTML
image of HTML image data for /beauty.jpg
image of HTML image data for /foo.png
image of HTML image data for /food.png
image of HTML image data for /bar.png
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章