java並發中ExecutorService的使用


java並發中ExecutorService的使用

ExecutorService是java中的一個異步執行的框架,通過使用ExecutorService可以方便的創建多線程執行環境。

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

創建ExecutorService

通常來說有兩種方法來創建ExecutorService。

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

ExecutorService executor = Executors.newFixedThreadPool(10); 復制代碼

除了newFixedThreadPool方法之外,Executors還包含了很多創建ExecutorService的方法。

第二種方法是直接創建一個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是有返回值的。我們分別看一下兩種情況的使用:

將task分配給ExecutorService,可以通過調用xecute(), submit(), invokeAny(), invokeAll()這幾個方法來實現。

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則是為了讓任務更加快速的執行完畢。

本文的代碼請參考github.com/ddean2009/l…


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM