前言:
上篇學習了線程Thread的使用,今天來學習一下線程池ExecutorService。
線程管理相關文章地址:
- Android線程管理之Thread使用總結
- Android線程管理之ExecutorService線程池
- Android線程管理之ThreadPoolExecutor自定義線程池
- Android線程管理之AsyncTask異步任務
- Android線程管理之ThreadLocal理解及應用場景
為什么要引入線程池?
1.)new Thread()的缺點
- 每次new Thread()耗費性能
- 調用new Thread()創建的線程缺乏管理,被稱為野線程,而且可以無限制創建,之間相互競爭,會導致過多占用系統資源導致系統癱瘓。
- 不利於擴展,比如如定時執行、定期執行、線程中斷
2.)采用線程池的優點
- 重用存在的線程,減少對象創建、消亡的開銷,性能佳
- 可有效控制最大並發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞
- 提供定時執行、定期執行、單線程、並發數控制等功能
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; }
Executor 接口
public interface Executor { void execute(Runnable command);//執行已提交的 Runnable 任務對象。此接口提供一種將任務提交與每個任務將如何運行的機制(包括線程使用的細節、調度等)分離開來的方法 }
Executors工廠類
通過Executors提供四種線程池,newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool。
1.)newFixedThreadPool創建一個可重用固定線程數的線程池,以共享的無界隊列方式來運行這些線程。
示例
ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 20; i++) { Runnable syncRunnable = new Runnable() { @Override public void run() { Log.e(TAG, Thread.currentThread().getName()); } }; executorService.execute(syncRunnable); }
運行結果:總共只會創建5個線程, 開始執行五個線程,當五個線程都處於活動狀態,再次提交的任務都會加入隊列等到其他線程運行結束,當線程處於空閑狀態時會被下一個任務復用
2.)newCachedThreadPool創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程
示例:
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); }
運行結果:可以看出緩存線程池大小是不定值,可以需要創建不同數量的線程,在使用緩存型池時,先查看池中有沒有以前創建的線程,如果有,就復用.如果沒有,就新建新的線程加入池中,緩存型池子通常用於執行一些生存期很短的異步型任務
3.)newScheduledThreadPool創建一個定長線程池,支持定時及周期性任務執行
schedule(Runnable command,long delay, TimeUnit unit)創建並執行在給定延遲后啟用的一次性操作
示例:表示從提交任務開始計時,5000毫秒后執行
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5); for (int i = 0; i < 20; i++) { Runnable syncRunnable = new Runnable() { @Override public void run() { Log.e(TAG, Thread.currentThread().getName()); } }; executorService.schedule(syncRunnable, 5000, TimeUnit.MILLISECONDS); }
運行結果和newFixedThreadPool類似,不同的是newScheduledThreadPool是延時一定時間之后才執行
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnitunit) 創建並執行一個在給定初始延遲后首次啟用的定期操作,后續操作具有給定的周期;也就是將在 initialDelay 后開始執行,然后在initialDelay+period 后執行,接着在 initialDelay + 2 * period 后執行,依此類推
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5); Runnable syncRunnable = new Runnable() { @Override public void run() { Log.e(TAG, Thread.currentThread().getName()); } }; executorService.scheduleAtFixedRate(syncRunnable, 5000, 3000, TimeUnit.MILLISECONDS);
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
創建並執行一個在給定初始延遲后首次啟用的定期操作,隨后,在每一次執行終止和下一次執行開始之間都存在給定的延遲
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5); Runnable syncRunnable = new Runnable() { @Override public void run() { Log.e(TAG, Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }; executorService.scheduleWithFixedDelay(syncRunnable, 5000, 3000, TimeUnit.MILLISECONDS);
3.)newSingleThreadExecutor創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行
示例
ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 20; i++) { Runnable syncRunnable = new Runnable() { @Override public void run() { Log.e(TAG, Thread.currentThread().getName()); } }; executorService.execute(syncRunnable); }
運行結果:只會創建一個線程,當上一個執行完之后才會執行第二個
通過ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();實現延時的單線程線程池
小結:
通過本文介紹了簡單的線程池使用,也可以通過ThreadPoolExecutor定義自己的線程池,后面再做學習總結。