java併發中ExecutorService的使用

java併發中ExecutorService的使用java

ExecutorService是java中的一個異步執行的框架,經過使用ExecutorService能夠方便的建立多線程執行環境。git

本文將會詳細的講解ExecutorService的具體使用。github

建立ExecutorService

一般來講有兩種方法來建立ExecutorService。多線程

第一種方式是使用Executors中的工廠類方法,例如:併發

ExecutorService executor = Executors.newFixedThreadPool(10);

除了newFixedThreadPool方法以外,Executors還包含了不少建立ExecutorService的方法。oracle

第二種方法是直接建立一個ExecutorService, 由於ExecutorService是一個interface,咱們須要實例化ExecutorService的一個實現。框架

這裏咱們使用ThreadPoolExecutor來舉例:異步

ExecutorService executorService =
            new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>());

爲ExecutorService分配Tasks

ExecutorService能夠執行Runnable和Callable的task。其中Runnable是沒有返回值的,而Callable是有返回值的。咱們分別看一下兩種狀況的使用:線程

Runnable runnableTask = () -> {
    try {
        TimeUnit.MILLISECONDS.sleep(300);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
};
 
Callable<String> callableTask = () -> {
    TimeUnit.MILLISECONDS.sleep(300);
    return "Task's execution";
};

將task分配給ExecutorService,能夠經過調用xecute(), submit(), invokeAny(), invokeAll()這幾個方法來實現。code

execute() 返回值是void,他用來提交一個Runnable task。

executorService.execute(runnableTask);

submit() 返回值是Future,它能夠提交Runnable task, 也能夠提交Callable task。 提交Runnable的有兩個方法:

<T> Future<T> submit(Runnable task, T result);

Future<?> submit(Runnable task);

第一個方法在返回傳入的result。第二個方法返回null。

再看一下callable的使用:

Future<String> future = 
  executorService.submit(callableTask);

invokeAny() 將一個task列表傳遞給executorService,並返回其中的一個成功返回的結果。

String result = executorService.invokeAny(callableTasks);

invokeAll() 將一個task列表傳遞給executorService,並返回全部成功執行的結果:

List<Future<String>> futures = executorService.invokeAll(callableTasks);

關閉ExecutorService

若是ExecutorService中的任務運行完畢以後,ExecutorService不會自動關閉。它會等待接收新的任務。若是須要關閉ExecutorService, 咱們須要調用shutdown() 或者 shutdownNow() 方法。

shutdown() 會當即銷燬ExecutorService,它會讓ExecutorServic中止接收新的任務,並等待現有任務所有執行完畢再銷燬。

executorService.shutdown();

shutdownNow()並不保證全部的任務都被執行完畢,它會返回一個未執行任務的列表:

List<Runnable> notExecutedTasks = executorService.shutdownNow();

oracle推薦的最佳關閉方法是和awaitTermination一塊兒使用:

executorService.shutdown();
       try {
           if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
               executorService.shutdownNow();
           }
       } catch (InterruptedException e) {
           executorService.shutdownNow();
       }

先中止接收任務,而後再等待必定的時間讓全部的任務都執行完畢,若是超過了給定的時間,則馬上結束任務。

## Future

submit() 和 invokeAll() 都會返回Future對象。以前的文章咱們已經詳細講過了Future。 這裏就只列舉一下怎麼使用:

Future<String> future = executorService.submit(callableTask);
String result = null;
try {
   result = future.get();
} catch (InterruptedException | ExecutionException e) {
   e.printStackTrace();
}

## ScheduledExecutorService

ScheduledExecutorService爲咱們提供了定時執行任務的機制。

咱們這樣建立ScheduledExecutorService:

ScheduledExecutorService executorService
                = Executors.newSingleThreadScheduledExecutor();

executorService的schedule方法,能夠傳入Runnable也能夠傳入Callable:

Future<String> future = executorService.schedule(() -> {
        // ...
        return "Hello world";
    }, 1, TimeUnit.SECONDS);
 
    ScheduledFuture<?> scheduledFuture = executorService.schedule(() -> {
        // ...
    }, 1, TimeUnit.SECONDS);

還有兩個比較相近的方法:

scheduleAtFixedRate( Runnable command, long initialDelay, long period, TimeUnit unit )

scheduleWithFixedDelay( Runnable command, long initialDelay, long delay, TimeUnit unit )

二者的區別是前者的period是以任務開始時間來計算的,後者是以任務結束時間來計算。

ExecutorService和 Fork/Join

java 7 引入了Fork/Join框架。 那麼二者的區別是什麼呢?

ExecutorService能夠由用戶來本身控制生成的線程,提供了對線程更加細粒度的控制。而Fork/Join則是爲了讓任務更加快速的執行完畢。

本文的代碼請參考https://github.com/ddean2009/learn-java-concurrency/tree/master/ExecutorService

更多教程請參考 flydean的博客

相關文章
相關標籤/搜索