Executor:是Java線程池的超級接口;提供一個execute(Runnable command)方法;我們一般用它的繼承接口ExecutorService。
Executors:是java.util.concurrent包下的一個類,提供了若干個靜態方法,用於生成不同類型的線程池。Executors一共可以創建下面這四類線程池:
newFixedThreadPool
創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
- newFixedThreadPool
創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。
newScheduledThreadPool 創建一個線程池,它可安排在給定延遲后運行命令或者定期地執行。
newSingleThreadExecutor 創建一個使用單個 worker 線程的 Executor,以無界隊列方式來運行該線程。
它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。
ExecutorService:它是線程池定義的一個接口,繼承Executor。有兩個實現類,分別為ThreadPoolExecutor,ScheduledThreadPoolExecutor。
線程池的繼承樹:
ExecutorService常用的幾個方法:
- execute(Runnable)從父類繼承過來的方法
- submit(Runnable)
- submit(Callable)
- invokeAny(...)
- invokeAll(...)
- shutdown()
execute方法:方法接收一個Runnable實例,並且異步的執行,請看下面的實例:
public class Demo1 { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); //創建一個單線程 executorService.execute(new Runnable() { //接收一個Runnable實例 public void run() { System.out.println("Asynchronous task"); } }); executorService.shutdown(); } }
這個方法有個問題,就是沒有辦法獲知task的執行結果。如果我們想獲得task的執行結果,我們可以傳入一個Callable的實例(下面會介紹)。
submit(Runnable)方法:返回一個Future對象,通過返回的Future對象,我們可以檢查提交的任務是否執行完畢。
public class Demo2 { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newSingleThreadExecutor(); //創建一個單線程 Future future = executorService.submit(new Runnable() { //接收一個Runnable實例 public void run() { System.out.println("Asynchronous task"); } }); System.out.println(future.get()); //任務執行結束返回null. executorService.shutdown(); } }
submit(Callable):與submit(Callable)類似,也會返回一個Future對象,但是除此之外,submit(Callable)接收的是一個Callable的實現,Callable接口中的call()
方法有一個返回值,可以返回任務的執行結果,而Runnable接口中的run()
方法是void
的,沒有返回值。
public class Demo1 { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newSingleThreadExecutor(); //創建一個單線程 Future<Object> future = executorService.submit(new Callable<Object>() { //接收一個Callable實例 public Object call() { System.out.println("Asynchronous task"); return "Callable Result"; } }); System.out.println("future.get()="+future.get()); executorService.shutdown(); } }
invokeAny(...):方法接收的是一個Callable的集合,執行這個方法不會返回Future,但是會返回所有Callable任務中其中一個任務的執行結果。這個方法也無法保證返回的是哪個任務的執行結果,反正是其中的某一個。
public class Demo2 { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<Callable<String>> callables = new HashSet<Callable<String>>(); callables.add(new Callable<String>(){ @Override public String call() throws Exception { // TODO Auto-generated method stub return "Result1"; } }); callables.add(new Callable<String>(){ @Override public String call() throws Exception { // TODO Auto-generated method stub return "Result2"; } }); callables.add(new Callable<String>(){ @Override public String call() throws Exception { // TODO Auto-generated method stub return "Result3"; } }); String result = executorService.invokeAny(callables); System.out.println(result); executorService.shutdown(); } }
invokeAll(...):與 invokeAny(...)
類似也是接收一個Callable集合,但是前者執行之后會返回一個Future的List,其中對應着每個Callable任務執行后的Future對象。
public class Demo3 { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<Callable<String>> callables = new HashSet<Callable<String>>(); callables.add(new Callable<String>(){ @Override public String call() throws Exception { // TODO Auto-generated method stub return "Result1"; } }); callables.add(new Callable<String>(){ @Override public String call() throws Exception { // TODO Auto-generated method stub return "Result2"; } }); callables.add(new Callable<String>(){ @Override public String call() throws Exception { // TODO Auto-generated method stub return "Result3"; } }); List<Future<String>> futures = executorService.invokeAll(callables); //返回一個Future的List集合 for(Future<String> future:futures){ System.out.println("future.get()="+future.get()); } executorService.shutdown(); } }
shutdown():我們使用完成ExecutorService之后應該關閉它,否則它里面的線程會一直處於運行狀態。
舉個例子,如果的應用程序是通過main()方法啟動的,在這個main()退出之后,如果應用程序中的ExecutorService沒有關閉,這個應用將一直運行。之所以會出現這種情況,是因為ExecutorService中運行的線程會阻止JVM關閉。
如果要關閉ExecutorService中執行的線程,我們可以調用ExecutorService.shutdown()
方法。在調用shutdown()方法之后,ExecutorService不會立即關閉,但是它不再接收新的任務,直到當前所有線程執行完成才會關閉,所有在shutdown()執行之前提交的任務都會被執行。
如果我們想立即關閉ExecutorService,我們可以調用ExecutorService.shutdownNow()
方法。這個動作將跳過所有正在執行的任務和被提交還沒有執行的任務。但是它並不對正在執行的任務做任何保證,有可能它們都會停止,也有可能執行完成。