Java線程池 ExecutorService了解一下
本篇主要涉及到的是java.util.concurrent包中的ExecutorService。ExecutorService就是Java中對線程池的實現。
一、ExecutorService介紹
ExecutorService是Java中對線程池定義的一個接口,它java.util.concurrent
包中,在這個接口中定義了和後臺任務執行相關的方法:
Java API對ExecutorService接口的實現有兩個,所以這兩個即是Java線程池具體實現類:
1. ThreadPoolExecutor
2. ScheduledThreadPoolExecutor
除此之外,ExecutorService還繼承了Executor
execute()
方法,最後我們看一下整個繼承樹:
二、ExecutorService的創建
創建一個什麽樣的ExecutorService的實例(即線程池)需要g根據具體應用場景而定,不過Java給我們提供了一個Executors工廠類
,它可以幫助我們很方便的創建各種類型ExecutorService線程池,Executors一共可以創建下面這四類線程池:
1. newCachedThreadPool 創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。 2. newFixedThreadPool 創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。3. newScheduledThreadPool 創建一個定長線程池,支持定時及周期性任務執行。 4. newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。
備註:Executors只是一個工廠類,它所有的方法返回的都是ThreadPoolExecutor
、ScheduledThreadPoolExecutor
這兩個類的實例。
三、ExecutorService的使用
ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(new Runnable() { public void run() { System.out.println("Asynchronous task"); } }); executorService.shutdown();
四、ExecutorService的執行
ExecutorService有如下幾個執行方法:
- execute(Runnable) - submit(Runnable) - submit(Callable) - invokeAny(...) - invokeAll(...)
4.1 execute(Runnable)
這個方法接收一個Runnable實例,並且異步的執行,請看下面的實例:
ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.execute(new Runnable() { public void run() { System.out.println("Asynchronous task"); } }); executorService.shutdown();
這個方法有個問題,就是沒有辦法獲知task的執行結果。如果我們想獲得task的執行結果,我們可以傳入一個Callable的實例(下面會介紹)。
4.2 submit(Runnable)
submit(Runnable)
和execute(Runnable)
區別是前者可以返回一個Future對象,通過返回的Future對象,我們可以檢查提交的任務是否執行完畢,請看下面執行的例子:
Future future = executorService.submit(new Runnable() { public void run() { System.out.println("Asynchronous task"); } }); future.get(); //returns null if the task has finished correctly.
如果任務執行完成,future.get()
方法會返回一個null。註意,future.get()方法會產生阻塞。
4.3 submit(Callable)
submit(Callable)
和submit(Runnable)
類似,也會返回一個Future對象,但是除此之外,submit(Callable)接收的是一個Callable的實現,Callable接口中的call()
方法有一個返回值,可以返回任務的執行結果,而Runnable接口中的run()
方法是void
的,沒有返回值。請看下面實例:
Future future = executorService.submit(new Callable(){ public Object call() throws Exception { System.out.println("Asynchronous Callable"); return "Callable Result"; } }); System.out.println("future.get() = " + future.get());
如果任務執行完成,future.get()方法會返回Callable任務的執行結果。註意,future.get()方法會產生阻塞。
4.4 invokeAny(…)
invokeAny(...)
方法接收的是一個Callable的集合,執行這個方法不會返回Future,但是會返回所有Callable任務中其中一個任務的執行結果。這個方法也無法保證返回的是哪個任務的執行結果,反正是其中的某一個。請看下面實例:
ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<Callable<String>> callables = new HashSet<Callable<String>>(); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 1"; } }); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 2"; } }); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 3"; } }); String result = executorService.invokeAny(callables); System.out.println("result = " + result); executorService.shutdown();
大家可以嘗試執行上面代碼,每次執行都會返回一個結果,並且返回的結果是變化的,可能會返回“Task2”也可是“Task1”或者其它。
4.5 invokeAll(…)
invokeAll(...)
與 invokeAny(...)
類似也是接收一個Callable集合,但是前者執行之後會返回一個Future的List,其中對應著每個Callable任務執行後的Future對象。情況下面這個實例:
ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<Callable<String>> callables = new HashSet<Callable<String>>(); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 1"; } }); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 2"; } }); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 3"; } }); List<Future<String>> futures = executorService.invokeAll(callables); for(Future<String> future : futures){ System.out.println("future.get = " + future.get()); } executorService.shutdown();
五、ExecutorService的關閉
當我們使用完成ExecutorService之後應該關閉它,否則它裏面的線程會一直處於運行狀態。
舉個例子,如果的應用程序是通過main()方法啟動的,在這個main()退出之後,如果應用程序中的ExecutorService沒有關閉,這個應用將一直運行。之所以會出現這種情況,是因為ExecutorService中運行的線程會阻止JVM關閉。
如果要關閉ExecutorService中執行的線程,我們可以調用ExecutorService.shutdown()
方法。在調用shutdown()方法之後,ExecutorService不會立即關閉,但是它不再接收新的任務,直到當前所有線程執行完成才會關閉,所有在shutdown()執行之前提交的任務都會被執行。
如果我們想立即關閉ExecutorService,我們可以調用ExecutorService.shutdownNow()
方法。這個動作將跳過所有正在執行的任務和被提交還沒有執行的任務。但是它並不對正在執行的任務做任何保證,有可能它們都會停止,也有可能執行完成。
原文鏈接:https://blog.csdn.net/suifeng3051/article/details/49443835
Java線程池 ExecutorService了解一下