java並發編程-----Executor線程池框架
在Java 5之後,並發編程引入了一堆新的啟動、調度和管理線程的API。
Executor框架便是Java 5中引入的,
其內部使用了線程池機制,它在java.util.cocurrent 包下,通過該框架來控制線程的啟動、執行和關閉,可以簡化並發編程的操作。因此,在Java 5之後,通過Executor來啟動線程比使用Thread的start方法更好,除了更易管理,效率更好(用線程池實現,節約開銷)外,還有關鍵的一點:有助於避免this逃逸問題——如果我們在構造器中啟動一個線程,因為另一個任務可能會在構造器結束之前開始執行,此時可能會訪問到初始化了一半的對象用Executor在構造器中。
Executor框架包括:線程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。
Executors方法介紹
Executors工廠類
通過Executors提供四種線程池,newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool。
1.public static ExecutorService newFixedThreadPool(int nThreads)
創建固定數目線程的線程池。
2.public static ExecutorService newCachedThreadPool()
創建一個可緩存的線程池,調用execute將重用以前構造的線程(如果線程可用)。如果現有線程沒有可用的,則創建一個新線 程並添加到池中。終止並從緩存中移除那些已有 60 秒鐘未被使用的線程。
3.public static ExecutorService newSingleThreadExecutor()
創建一個單線程化的Executor。
4.public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
實例:
ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 100; i++) { Runnable syncRunnable = new Runnable() { @Override public void run() { Log.e(TAG, Thread.currentThread().getName()); } }; executorService.execute(syncRunnable); }
ExecutorService
ExecutorService是一個接口,ExecutorService接口繼承了Executor接口,定義了一些生命周期的方法。
public interface ExecutorService extends Executor { void shutdown();//順次地關閉ExecutorService,停止接收新的任務,等待所有已經提交的任務執行完畢之後,關閉ExecutorService List<Runnable> shutdownNow();//阻止等待任務啟動並試圖停止當前正在執行的任務,停止接收新的任務,返回處於等待的任務列表 boolean isShutdown();//判斷線程池是否已經關閉 boolean isTerminated();//如果關閉後所有任務都已完成,則返回 true。註意,除非首先調用 shutdown 或 shutdownNow,否則 isTerminated 永不為 true。 boolean awaitTermination(long timeout, TimeUnit unit)//等待(阻塞)直到關閉或最長等待時間或發生中斷,timeout - 最長等待時間 ,unit - timeout 參數的時間單位 如果此執行程序終止,則返回 true;如果終止前超時期滿,則返回 false <T> Future<T> submit(Callable<T> task);//提交一個返回值的任務用於執行,返回一個表示任務的未決結果的 Future。該 Future 的 get 方法在成功完成時將會返回該任務的結果。 <T> Future<T> submit(Runnable task, T result);//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。該 Future 的 get 方法在成功完成時將會返回給定的結果。 Future<?> submit(Runnable task);//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。該 Future 的 get 方法在成功 完成時將會返回 null <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)//執行給定的任務,當所有任務完成時,返回保持任務狀態和結果的 Future 列表。返回列表的所有元素的 Future.isDone() 為 true。 throws InterruptedException; <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)//執行給定的任務,當所有任務完成時,返回保持任務狀態和結果的 Future 列表。返回列表的所有元素的 Future.isDone() 為 true。 throws InterruptedException; <T> T invokeAny(Collection<? extends Callable<T>> tasks)//執行給定的任務,如果在給定的超時期滿前某個任務已成功完成(也就是未拋出異常),則返回其結果。一旦正常或異常返回後,則取消尚未完成的任務。 throws InterruptedException, ExecutionException; <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
ExecutorService接口繼承自Executor接口,它提供了更豐富的實現多線程的方法,比如,ExecutorService提供了關閉自己的方法,以及可為跟蹤一個或多個異步任務執行狀況而生成 Future 的方法。 可以調用ExecutorService的shutdown()方法來平滑地關閉 ExecutorService,調用該方法後,將導致ExecutorService停止接受任何新的任務且等待已經提交的任務執行完成(已經提交的任務會分兩類:一類是已經在執行的,另一類是還沒有開始執行的),當所有已經提交的任務執行完畢後將會關閉ExecutorService。因此我們一般用該接口來實現和管理多線程。
ExecutorService的生命周期包括三種狀態:運行、關閉、終止。創建後便進入運行狀態,當調用了shutdown()方法時,便進入關閉狀態,此時意味著ExecutorService不再接受新的任務,但它還在執行已經提交了的任務,當素有已經提交了的任務執行完後,便到達終止狀態。如果不調用shutdown()方法,ExecutorService會一直處在運行狀態,不斷接收新的任務,執行新的任務,服務器端一般不需要關閉它,保持一直運行即可。
Executor執行Runnable任務
一旦Runnable任務傳遞到execute()方法,該方法便會自動在一個線程上執行。下面是是Executor執行Runnable任務的示例代碼:
public class TestCachedThreadPool{ public static void main(String[] args){ ExecutorService executorService = Executors.newCachedThreadPool(); // ExecutorService executorService = Executors.newFixedThreadPool(5); // ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; i++){ executorService.execute(new TestRunnable()); System.out.println("************* a" + i + " *************"); } executorService.shutdown(); } } class TestRunnable implements Runnable{ public void run(){ System.out.println(Thread.currentThread().getName() + "線程被調用了。"); } }
Executor執行Callable任務
在Java 5之後,任務分兩類:一類是實現了Runnable接口的類,一類是實現了Callable接口的類。兩者都可以被ExecutorService執行,但是Runnable任務沒有返回值,而Callable任務有返回值。並且Callable的call()方法只能通過ExecutorService的submit(Callable task) 方法來執行,並且返回一個 Future,是表示任務等待完成的 Future。
實例:
public class CallableDemo{ public static void main(String[] args){ ExecutorService executorService = Executors.newCachedThreadPool(); List<Future<String>> resultList = new ArrayList<Future<String>>(); //創建10個任務並執行 for (int i = 0; i < 10; i++){ //使用ExecutorService執行Callable類型的任務,並將結果保存在future變量中 Future<String> future = executorService.submit(new TaskWithResult(i)); //將任務執行結果存儲到List中 resultList.add(future); } //遍歷任務的結果 for (Future<String> fs : resultList){ try{ while(!fs.isDone);//Future返回如果沒有完成,則一直循環等待,直到Future返回完成 System.out.println(fs.get()); //打印各個線程(任務)執行的結果 }catch(InterruptedException e){ e.printStackTrace(); }catch(ExecutionException e){ e.printStackTrace(); }finally{ //啟動一次順序關閉,執行以前提交的任務,但不接受新任務 executorService.shutdown(); } } } } class TaskWithResult implements Callable<String>{ private int id; public TaskWithResult(int id){ this.id = id; } /** * 任務的具體過程,一旦任務傳給ExecutorService的submit方法, * 則該方法自動在一個線程上執行 */ public String call() throws Exception { System.out.println("call()方法被自動調用!!! " + Thread.currentThread().getName()); //該返回結果將被Future的get方法得到 return "call()方法被自動調用,任務返回的結果是:" + id + " " + Thread.currentThread().getName(); } }
自定義線程池
自定義線程池,可以用ThreadPoolExecutor類創建,它有多個構造方法來創建線程池,用該類很容易實現自定義的線程池,這裏先貼上示例程序:
public class ThreadPoolTest{ public static void main(String[] args){ //創建等待隊列 BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(20); //創建線程池,池中保存的線程數為3,允許的最大線程數為5 ThreadPoolExecutor pool = new ThreadPoolExecutor(3,5,50,TimeUnit.MILLISECONDS,bqueue); //創建七個任務 Runnable t1 = new MyThread(); Runnable t2 = new MyThread(); Runnable t3 = new MyThread(); Runnable t4 = new MyThread(); Runnable t5 = new MyThread(); Runnable t6 = new MyThread(); Runnable t7 = new MyThread(); //每個任務會在一個線程上執行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5); pool.execute(t6); pool.execute(t7); //關閉線程池 pool.shutdown(); } } class MyThread implements Runnable{ @Override public void run(){ System.out.println(Thread.currentThread().getName() + "正在執行。。。"); try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } } }
java並發編程-----Executor線程池框架