Android线程池封装库
生活随笔
收集整理的這篇文章主要介紹了
Android线程池封装库
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄介紹
- 1.遇到的問題和需求
- 1.1 遇到的問題有哪些
- 1.2 遇到的需求
- 1.3 多線程通過實現Runnable弊端
- 1.4 為什么要用線程池
- 2.封裝庫具有的功能
- 2.1 常用的功能
- 3.封裝庫的具體使用
- 3.1 一鍵集成
- 3.2 在application中初始化庫
- 3.3 最簡單的runnable線程調用方式
- 3.4 最簡單的異步回調
- 4.線程池封裝思路介紹
- 4.1 自定義Runnable和Callable類
- 4.2 添加回調接口Callback
- 4.3 創建線程池配置文件
- 4.4 創建java和android平臺消息器
- 4.5 創建PoolThread繼承Executor
- 4.6 使用builder模式獲取線程池對象
- 4.7 靈活創建線程池[重點]
- 4.8 啟動線程池中的任務
- 4.9 如何關閉線程池操作
- 5.其他介紹
- 5.1 參考的開源案例
- 5.2 參考的博客
好消息
- 博客筆記大匯總【16年3月到至今】,包括Java基礎及深入知識點,Android技術博客,Python學習筆記等等,還包括平時開發中遇到的bug匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計N篇[近100萬字,陸續搬到網上],轉載請注明出處,謝謝!
- 鏈接地址:https://github.com/yangchong211/YCBlogs
- 如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起于忽微,量變引起質變!
0.前言介紹
- 輕量級線程池封裝庫,支持線程執行過程中狀態回調監測(包含成功,失敗,異常等多種狀態);支持創建異步任務,并且可以設置線程的名稱,延遲執行時間,線程優先級,回調callback等;可以根據自己需要創建自己需要的線程池,一共有四種;線程異常時,可以打印異常日志,避免崩潰。
- 關于線程池,對于開發來說是十分重要,但是又有點難以理解或者運用。關于寫線程池的博客網上已經有很多了,但是一般很少有看到的實際案例或者封裝的庫,許多博客也僅僅是介紹了線程池的概念,方法,或者部分源碼分析,那么為了方便管理線程任務操作,所以才想結合實際案例是不是更容易理解線程池,更多可以參考代碼。
線程池封裝庫GitHub鏈接:https://github.com/yangchong211/YCThreadPool
1.遇到的問題和需求
1.1 遇到的問題有哪些?
- 繼承Thread,或者實現接口Runnable來開啟一個子線程,無法準確地知道線程什么時候執行完成并獲得到線程執行完成后返回的結果
- 當線程出現異常的時候,如何避免導致崩潰問題?博客
1.2 遇到的需求
- 如何在實際開發中配置線程的優先級
- 開啟一個線程,是否可以監聽Runnable接口中run方法操作的過程,比如監聽線程的狀態開始,成功,異常,完成等多種狀態。
- 開啟一個線程,是否可以監聽Callable<T>接口中call()方法操作的過程,比如監聽線程的狀態開始,錯誤異常,完成等多種狀態。
1.3 多線程通過實現Runnable弊端
- 1.3.1 一般開啟線程的操作如下所示 new Thread(new Runnable() {@Overridepublic void run() {//做一些任務} }).start();
- 創建了一個線程并執行,它在任務結束后GC會自動回收該線程。
- 在線程并發不多的程序中確實不錯,而假如這個程序有很多地方需要開啟大量線程來處理任務,那么如果還是用上述的方式去創建線程處理的話,那么將導致系統的性能表現的非常糟糕。博客
- 1.3.2 主要的弊端有這些,可能總結并不全面
- 大量的線程創建、執行和銷毀是非常耗cpu和內存的,這樣將直接影響系統的吞吐量,導致性能急劇下降,如果內存資源占用的比較多,還很可能造成OOM
- 大量的線程的創建和銷毀很容易導致GC頻繁的執行,從而發生內存抖動現象,而發生了內存抖動,對于移動端來說,最大的影響就是造成界面卡頓
- 線程的創建和銷毀都需要時間,當有大量的線程創建和銷毀時,那么這些時間的消耗則比較明顯,將導致性能上的缺失
1.4 為什么要用線程池
- 使用線程池管理線程優點
- ①降低系統資源消耗,通過重用已存在的線程,降低線程創建和銷毀造成的消耗;
- ②提高系統響應速度,當有任務到達時,無需等待新線程的創建便能立即執行;
- ③方便線程并發數的管控,線程若是無限制的創建,不僅會額外消耗大量系統資源,更是占用過多資源而阻塞系統或oom等狀況,從而降低系統的穩定性。線程池能有效管控線程,統一分配、調優,提供資源使用率;
- ④更強大的功能,線程池提供了定時、定期以及可控線程數等功能的線程池,使用方便簡單。
1.5 線程池執行流程
- 大概的流程圖如下
- 文字描述如下
- ①如果在線程池中的線程數量沒有達到核心的線程數量,這時候就回啟動一個核心線程來執行任務。
- ②如果線程池中的線程數量已經超過核心線程數,這時候任務就會被插入到任務隊列中排隊等待執行。
- ③由于任務隊列已滿,無法將任務插入到任務隊列中。這個時候如果線程池中的線程數量沒有達到線程池所設定的最大值,那么這時候就會立即啟動一個非核心線程來執行任務。
- ④如果線程池中的數量達到了所規定的最大值,那么就會拒絕執行此任務,這時候就會調用RejectedExecutionHandler中的rejectedExecution方法來通知調用者。博客
2.封裝庫具有的功能
2.1 常用的功能
- 支持線程執行過程中狀態回調監測(包含成功,失敗,異常等多種狀態)
- 支持線程異常檢測,并且可以打印異常日志
- 支持設置線程屬性,比如名稱,延時時長,優先級,callback
- 支持異步開啟線程任務,支持監聽異步回調監聽
- 方便集成,方便使用,可以靈活選擇創建不同的線程池
3.封裝庫的具體使用
3.1 一鍵集成
- compile 'cn.yc:YCThreadPoolLib:1.3.0'
3.2 在application中初始化庫
- 代碼如下所示 public class App extends Application{private static App instance;private PoolThread executor;public static synchronized App getInstance() {if (null == instance) {instance = new App();}return instance;}public App(){}@Overridepublic void onCreate() {super.onCreate();instance = this;//初始化線程池管理器initThreadPool();}/*** 初始化線程池管理器*/private void initThreadPool() {// 創建一個獨立的實例進行使用executor = PoolThread.ThreadBuilder.createFixed(5).setPriority(Thread.MAX_PRIORITY).setCallback(new LogCallback()).build();}/*** 獲取線程池管理器對象,統一的管理器維護所有的線程池* @return executor對象 */ public PoolThread getExecutor(){ return executor; } } //自定義回調監聽callback,可以全局設置,也可以單獨設置。都行 public class LogCallback implements ThreadCallback { private final String TAG = "LogCallback"; @Override public void onError(String name, Throwable t) { Log.e(TAG, "LogCallback"+"------onError"+"-----"+name+"----"+Thread.currentThread()+"----"+t.getMessage()); } @Override public void onCompleted(String name) { Log.e(TAG, "LogCallback"+"------onCompleted"+"-----"+name+"----"+Thread.currentThread()); } @Override public void onStart(String name) { Log.e(TAG, "LogCallback"+"------onStart"+"-----"+name+"----"+Thread.currentThread()); } }
3.3 最簡單的runnable線程調用方式
- 關于設置callback回調監聽,我這里在app初始化的時候設置了全局的logCallBack,所以這里沒有添加,對于每個單獨的執行任務,可以添加獨立callback。 PoolThread executor = App.getInstance().getExecutor();executor.setName("最簡單的線程調用方式");executor.setDeliver(new AndroidDeliver());executor.execute(new Runnable() {@Overridepublic void run() {Log.e("MainActivity","最簡單的線程調用方式");}});
3.4 最簡單的異步回調
- 如下所示 PoolThread executor = App.getInstance().getExecutor();executor.setName("異步回調");executor.setDelay(2,TimeUnit.MILLISECONDS);// 啟動異步任務executor.async(new Callable<Login>(){@Overridepublic Login call() throws Exception {// 做一些操作return null;}}, new AsyncCallback<Login>() {@Overridepublic void onSuccess(Login user) {Log.e("AsyncCallback","成功");}@Overridepublic void onFailed(Throwable t) {Log.e("AsyncCallback","失敗"); } @Override public void onStart(String threadName) { Log.e("AsyncCallback","開始"); } });
4.線程池封裝思路介紹
4.1 自定義Runnable和自定義Callable類
-
4.1.1 首先看看Runnable和Callable接口代碼
public interface Runnable {public void run(); }public interface Callable<V> {V call() throws Exception; } -
4.1.2 Runnable和Callable接口是干什么的
-
Runnable 從 JDK1.0 開始就有了,Callable 是在 JDK1.5 增加的。
-
Thread調用了Runnable接口中的方法用來在線程中執行任務。Runnable 和 Callable 都代表那些要在不同的線程中執行的任務。
-
Thread調用了Runnable接口中的方法用來在線程中執行任務。博客
- 4.1.3 Runnable和Callable接口有何區別
- 它們的主要區別是 Callable 的 call() 方法可以返回值和拋出異常,而 Runnable 的 run() 方法沒有這些功能。Callable 可以返回裝載有計算結果的 Future 對象。博客
- 比較兩個接口,可以得出這樣結論:
- Callable 的任務執行后可返回值,而 Runnable 的任務是不能返回值的
- call() 方法可以拋出異常,run()方法不可以的
- 運行 Callable 任務可以拿到一個 Future 對象,表示異步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,并檢索計算的結果。通過 Future 對象可以了解任務執行情況,可取消任務的執行,還可獲取執行結果;
- 4.1.4 自定義Runnable包裝類,重點看run方法代碼邏輯 public final class RunnableWrapper implements Runnable {private String name;private CallbackDelegate delegate;private Runnable runnable;private Callable callable;public RunnableWrapper(ThreadConfigs configs) {this.name = configs.name;this.delegate = new CallbackDelegate(configs.callback, configs.deliver, configs.asyncCallback);}/*** 啟動異步任務,普通的* @param runnable runnable* @return 對象*/public RunnableWrapper setRunnable(Runnable runnable) {this.runnable = runnable;return this;}/*** 異步任務,回調用于接收可調用任務的結果* @param callable callable* @return 對象*/public RunnableWrapper setCallable(Callable callable) {this.callable = callable;return this;}/*** 自定義xxRunnable繼承Runnable,實現run方法 * 詳細可以看我的GitHub:https://github.com/yangchong211 */ @Override public void run() { Thread current = Thread.currentThread(); ThreadToolUtils.resetThread(current, name, delegate); //開始 delegate.onStart(name); //注意需要判斷runnable,callable非空 // avoid NullPointException if (runnable != null) { runnable.run(); } else if (callable != null) { try { Object result = callable.call(); //監聽成功 delegate.onSuccess(result); } catch (Exception e) { //監聽異常 delegate.onError(name, e); } } //監聽完成 delegate.onCompleted(name); } }
- 4.1.5 自定義Callable<T>包裝類,重點看call方法代碼邏輯 public final class CallableWrapper<T> implements Callable<T> {private String name;private ThreadCallback callback;private Callable<T> proxy;/*** 構造方法* @param configs thread配置,主要參數有:線程name,延遲time,回調callback,異步callback * @param proxy 線程優先級 */ public CallableWrapper(ThreadConfigs configs, Callable<T> proxy) { this.name = configs.name; this.proxy = proxy; this.callback = new CallbackDelegate(configs.callback, configs.deliver, configs.asyncCallback); } /** * 詳細可以看我的GitHub:https://github.com/yangchong211 * 自定義Callable繼承Callable<T>類,Callable 是在 JDK1.5 增加的。 * Callable 的 call() 方法可以返回值和拋出異常 * @return 泛型 * @throws Exception 異常 */ @Override public T call() { ThreadToolUtils.resetThread(Thread.currentThread(),name,callback); if (callback != null) { //開始 callback.onStart(name); } T t = null; try { t = proxy == null ? null : proxy.call(); } catch (Exception e) { e.printStackTrace(); //異常錯誤 if(callback!=null){ callback.onError(name,e); } }finally { //完成 if (callback != null) { callback.onCompleted(name); } } return t; } }
4. 添加回調接口AsyncCallback和ThreadCallback
- 注意,這個寫的自定義callback,需要添加多種狀態,你可以自定義其他狀態??赐炅诉@里再回過頭看看RunnableWrapper中run方法和CallableWrapper中call方法的邏輯。博客
- 4.0 為什么要這樣設計
- 它可以讓程序員準確地知道線程什么時候執行完成并獲得到線程執行完成后返回的結果。
- AsyncCallback,在這個類中,可以看到三種狀態[這個是在自定義Runnable中的run方法中實現],并且成功時可以攜帶結果,在異常時還可以打印異常日志。
- ThreadCallback,在這個類中,可以看到三種狀態[這個是在自定義Callable<T>中的call方法中實現],并且在異常時可以打印異常日志,在開始和完成時可以打印線程名稱
-
4.1 AsyncCallback類代碼如下所示
/*** <pre>* @author 楊充* blog https://www.jianshu.com/p/53017c3fc75d* time* desc 異步callback回調接口* revise* GitHub https://github.com/yangchong211* </pre>*/ public interface AsyncCallback<T> {/*** 成功時調用* @param t 泛型 */ void onSuccess(T t); /** * 異常時調用 * @param t 異常 */ void onFailed(Throwable t); /** * 通知用戶任務開始運行 * @param threadName 正在運行線程的名字 */ void onStart(String threadName); } -
4.2 ThreadCallback類代碼如下所示
/*** <pre>* @author: yangchong* blog : https://github.com/yangchong211* time :* desc : 一個回調接口,用于通知用戶任務的狀態回調委托類* 線程的名字可以自定義* revise:* </pre>*/ public interface ThreadCallback {/*** 當線程發生錯誤時,將調用此方法。* @param threadName 正在運行線程的名字* @param t 異常 */ void onError(String threadName, Throwable t); /** * 通知用戶知道它已經完成 * @param threadName 正在運行線程的名字 */ void onCompleted(String threadName); /** * 通知用戶任務開始運行 * @param threadName 正在運行線程的名字 */ void onStart(String threadName); }
4.3 創建線程池配置文件
- 為什么要添加配置文件,配置文件的作用主要是存儲當前任務的某些配置,比如線程的名稱,回調callback等等這些參數。還可以用于參數的傳遞! public final class ThreadConfigs {/*** 線程的名稱* 通過setName方法設置*/public String name;/*** 線程執行延遲的時間* 通過setDelay方法設置 */ public long delay; /** * 線程執行者 * JAVA或者ANDROID */ public Executor deliver; /** * 用戶任務的狀態回調callback */ public ThreadCallback callback; /** * 異步callback回調callback */ public AsyncCallback asyncCallback; }
4.4 創建java平臺和android平臺消息器Executor
- 在android環境下,想一想callback回調類中的幾個方法,比如回調失敗,回調成功,或者回調完成,可能會做一些操作UI界面的操作邏輯,那么都知道子線程是不能更新UI的,所以必須放到主線程中操作。
- 但是在Java環境下,回調方法所運行的線程與任務執行線程其實可以保持一致。
- 因此,這里需要設置該消息器用來區別回調的邏輯。主要作用是指定回調任務需要運行在什么線程之上。
- 4.4.1 android環境下?
- 4.4.2 java環境下?
- 4.4.3 如何判斷環境是java環境還是Android環境呢 public final class ThreadToolUtils {/*** 標志:是否在android平臺上*/public static boolean isAndroid;/** 靜態代碼塊* 判斷是否是android環境 * Class.forName(xxx.xx.xx) 返回的是一個類對象 * 首先要明白在java里面任何class都要裝載在虛擬機上才能運行。 */ static { try { Class.forName("android.os.Build"); isAndroid = true; } catch (Exception e) { isAndroid = false; } } }
4.5 創建PoolThread繼承Executor
- 這里只是展示部分代碼,如果想看完整的代碼,可以直接看案例。博客
- 4.5.1 繼承Executor接口,并且實現execute方法 public final class PoolThread implements Executor{/*** 啟動任務* 這個是實現接口Executor中的execute方法* 提交任務無返回值 * @param runnable task,注意添加非空注解 */ @Override public void execute (@NonNull Runnable runnable) { //獲取線程thread配置信息 ThreadConfigs configs = getLocalConfigs(); //設置runnable任務 runnable = new RunnableWrapper(configs).setRunnable(runnable); //啟動任務 DelayTaskDispatcher.get().postDelay(configs.delay, pool, runnable); //重置線程Thread配置 resetLocalConfigs(); } /** * 當啟動任務或者發射任務之后需要調用該方法 * 重置本地配置,置null */ private synchronized void resetLocalConfigs() { local.set(null); } /** * 注意需要用synchronized修飾,解決了多線程的安全問題 * 獲取本地配置參數 * @return */ private synchronized ThreadConfigs getLocalConfigs() { ThreadConfigs configs = local.get(); if (configs == null) { configs = new ThreadConfigs(); configs.name = defName; configs.callback = defCallback; configs.deliver = defDeliver; local.set(configs); } return configs; } }
4.6 使用builder模式獲取線程池對象
- 4.6.1 看下builder模式下代碼
- 如果還不是很熟悉builder模式,歡迎閱讀我的另外一篇文章之——設計模式之二:Builder模式:https://www.jianshu.com/p/246b01ca84c2
- 也可以看Android源碼設計模式這本書,很不錯
- 直接列出代碼,如下所示: public final class PoolThread implements Executor{//省略部分代碼……public static class ThreadBuilder {final static int TYPE_CACHE = 0;final static int TYPE_FIXED = 1;final static int TYPE_SINGLE = 2;final static int TYPE_SCHEDULED = 3;int type;int size;int priority = Thread.NORM_PRIORITY;String name;ThreadCallback callback;Executor deliver;ExecutorService pool;private ThreadBuilder(int size, int type, ExecutorService pool) {this.size = Math.max(1, size);this.type = type;this.pool = pool;}/*** 通過Executors.newSingleThreadExecutor()創建線程池* 內部只有一個核心線程,所有任務進來都要排隊按順序執行*/public static ThreadBuilder create(ExecutorService pool) {return new ThreadBuilder(1, TYPE_SINGLE, pool);}/*** 通過Executors.newCachedThreadPool()創建線程池 * 它是一個數量無限多的線程池,都是非核心線程,適合執行大量耗時小的任務 */ public static ThreadBuilder createCacheable() { return new ThreadBuilder(0, TYPE_CACHE, null); } /** * 通過Executors.newFixedThreadPool()創建線程池 * 線程數量固定的線程池,全部為核心線程,響應較快,不用擔心線程會被回收。 */ public static ThreadBuilder createFixed(int size) { return new ThreadBuilder(size, TYPE_FIXED, null); } /** * 通過Executors.newScheduledThreadPool()創建線程池 * 有數量固定的核心線程,且有數量無限多的非核心線程,適合用于執行定時任務和固定周期的重復任務 */ public static ThreadBuilder createScheduled(int size) { return new ThreadBuilder(size, TYPE_SCHEDULED, null); } /** * 通過Executors.newSingleThreadPool()創建線程池 * 內部只有一個核心線程,所有任務進來都要排隊按順序執行 * 和create區別是size數量 */ public static ThreadBuilder createSingle() { return new ThreadBuilder(0, TYPE_SINGLE, null); } /** * 將默認線程名設置為“已使用”。 */ public ThreadBuilder setName (@NonNull String name) { if (name.length()>0) { this.name = name; } return this; } /** * 將默認線程優先級設置為“已使用”。 */ public ThreadBuilder setPriority (int priority) { this.priority = priority; return this; } /** * 將默認線程回調設置為“已使用”。 */ public ThreadBuilder setCallback (ThreadCallback callback) { this.callback = callback; return this; } /** * 設置默認線程交付使用 */ public ThreadBuilder setDeliver(Executor deliver) { this.deliver = deliver; return this; } /** * 創建用于某些配置的線程管理器。 * @return 對象 */ public PoolThread build () { //最大值 priority = Math.max(Thread.MIN_PRIORITY, priority); //最小值 priority = Math.min(Thread.MAX_PRIORITY, priority); size = Math.max(1, size); if (name==null || name.length()==0) { // 如果沒有設置名字,那么就使用下面默認的線程名稱 switch (type) { case TYPE_CACHE: name = "CACHE"; break; case TYPE_FIXED: name = "FIXED"; break; case TYPE_SINGLE: name = "SINGLE"; break; default: name = "POOL_THREAD"; break; } } if (deliver == null) { if (ThreadToolUtils.isAndroid) { deliver = AndroidDeliver.getInstance(); } else { deliver = JavaDeliver.getInstance(); } } return new PoolThread(type, size, priority, name, callback, deliver, pool); } } }
- 4.6.2 添加設置thread配置信息的方法 /*** 為當前的任務設置線程名。* @param name 線程名字* @return PoolThread*/ public PoolThread setName(String name) {getLocalConfigs().name = name;return this; }/*** 設置當前任務的線程回調,如果未設置,則應使用默認回調。* @param callback 線程回調* @return PoolThread*/ public PoolThread setCallback (ThreadCallback callback) {getLocalConfigs().callback = callback;return this; }/*** 設置當前任務的延遲時間. * 只有當您的線程池創建時,它才會產生效果。 * @param time 時長 * @param unit time unit * @return PoolThread */ public PoolThread setDelay (long time, TimeUnit unit) { long delay = unit.toMillis(time); getLocalConfigs().delay = Math.max(0, delay); return this; } /** * 設置當前任務的線程傳遞。如果未設置,則應使用默認傳遞。 * @param deliver thread deliver * @return PoolThread */ public PoolThread setDeliver(Executor deliver){ getLocalConfigs().deliver = deliver; return this; }
- 4.6.3 看下builder模式下創建對象的代碼
- 通過調用ThreadBuilder類中的build()方法創建屬于自己的線程池。
- 最后通過new PoolThread(type, size, priority, name, callback, deliver, pool)創建對象,并且作為返回值返回。
- 然后再來看看PoolThread方法,這部分看目錄4.7部分介紹。博客
4.7 靈活創建線程池[重點]
- 4.7.1 創建線程池的五種方法
- 通過Executors的工廠方法獲取這五種線程池
- 通過Executors的工廠方法來創建線程池極其簡便,其實它的內部還是通過new ThreadPoolExecutor(…)的方式創建線程池的,具體可以看看源碼,這里省略呢…… ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); ExecutorService singleThreadPool = Executors.newSingleThreadExecutor(); ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); ScheduledExecutorService singleThreadScheduledPool = Executors.newSingleThreadScheduledExecutor();
- 4.7.2 靈活創建不同類型線程池
- 設計的時候,希望能夠選擇性地創建自己想要的線程池,并且動態設置線程的數量,還可以設置線程優先級。
- 4.7.2.1 創建不同類型線程池代碼如下所示: /*** 創建線程池,目前支持以下四種* @param type 類型* @param size 數量size* @param priority 優先級* @return*/ private ExecutorService createPool(int type, int size, int priority) {switch (type) {case Builder.TYPE_CACHE://它是一個數量無限多的線程池,都是非核心線程,適合執行大量耗時小的任務 return Executors.newCachedThreadPool(new DefaultFactory(priority)); case Builder.TYPE_FIXED: //線程數量固定的線程池,全部為核心線程,響應較快,不用擔心線程會被回收。 return Executors.newFixedThreadPool(size, new DefaultFactory(priority)); case Builder.TYPE_SCHEDULED: //有數量固定的核心線程,且有數量無限多的非核心線程,適合用于執行定時任務和固定周期的重復任務 return Executors.newScheduledThreadPool(size, new DefaultFactory(priority)); case Builder.TYPE_SINGLE: default: //內部只有一個核心線程,所有任務進來都要排隊按順序執行 return Executors.newSingleThreadExecutor(new DefaultFactory(priority)); } }
- 4.7.2.1 了解一下ThreadFactory接口作用
- 關于ThreadFactory接口的源代碼如下所示:
- 以看到ThreadFactory中,只有一個newThread方法,它負責接收一個Runnable對象,并將其封裝到Thread對象中,進行執行。
- 通過有道詞典對這個類的說明進行翻譯是:根據需要創建新線程的對象。使用線程工廠可以消除對{@link Thread#Thread(Runnable)新線程}的硬連接,從而使應用程序能夠使用特殊的線程子類、優先級等。 public interface ThreadFactory {/*** Constructs a new {@code Thread}. Implementations may also initialize* priority, name, daemon status, {@code ThreadGroup}, etc.** @param r a runnable to be executed by new thread instance* @return constructed thread, or {@code null} if the request to* create a thread is rejected*/Thread newThread(Runnable r); }
- 4.7.2.3 創建默認MyThreadFactory繼承ThreadFactory
- 創建一個默認的MyThreadFactory,并且這個類繼承ThreadFactory,實現接口中的newThread方法。然后在newThread方法中創建線程,并且設置線程優先級。
- 創建一個優先級線程池非常有用,它可以在線程池中線程數量不足或系統資源緊張時,優先處理我們想要先處理的任務,而優先級低的則放到后面再處理,這極大改善了系統默認線程池以FIFO方式處理任務的不靈活。
- 代碼如下所示 public class MyThreadFactory implements ThreadFactory {private int priority;public MyThreadFactory(int priority) {this.priority = priority;}@Overridepublic Thread newThread(@NonNull Runnable runnable) {Thread thread = new Thread(runnable);thread.setPriority(priority);return thread;}}
4.8 啟動線程池中的任務
- 具體邏輯看DelayTaskExecutor中的postDelay方法 /*** 啟動* @param delay 延遲執行的時間,注意默認單位是TimeUnit.MILLISECONDS* @param pool pool線程池* @param task runnable*/ void postDelay(long delay, final ExecutorService pool, final Runnable task) {if (delay == 0) {//如果時間是0,那么普通開啟 pool.execute(task); return; } //延時操作 dispatcher.schedule(new Runnable() { @Override public void run() { //在將來的某個時間執行給定的命令。該命令可以在新線程、池線程或調用線程中執行 pool.execute(task); } }, delay, TimeUnit.MILLISECONDS); }
4.9 如何關閉線程池操作
- 代碼如下所示 /*** 關閉線程池操作*/ public void stop(){ try { // shutdown只是起到通知的作用 // 只調用shutdown方法結束線程池是不夠的 pool.shutdown(); // (所有的任務都結束的時候,返回TRUE) if(!pool.awaitTermination(0, TimeUnit.MILLISECONDS)){ // 超時的時候向線程池中所有的線程發出中斷(interrupted)。 pool.shutdownNow(); } } catch (InterruptedException e) { // awaitTermination方法被中斷的時候也中止線程池中全部的線程的執行。 e.printStackTrace(); } finally { pool.shutdownNow(); } }
5.其他介紹
5.1 參考的開源案例
- Thread,Java多線程核心技術:https://github.com/boostorg/thread
- threadpool4j:https://github.com/aofeng/threadpool4j
- TickThreading:https://github.com/MinimallyCorrect/TickThreading
- MOBIN-F:https://github.com/MOBIN-F/Thread
- litesuits:https://github.com/litesuits/android-lite-async
5.2 參考的博客
- 自己封裝的簡單ThreadFactory:https://blog.csdn.net/hbdatouerzi/article/details/73715668
- Android 多線程 線程池原理 封裝線程池:https://blog.csdn.net/xiangyunwan/article/details/72550948
- Android 自定義線程池的實戰:https://www.cnblogs.com/zhaoyanjun/p/5761776.html
- android線程及線程池:https://www.jianshu.com/p/d79dab197d5a
其他介紹
01.關于博客匯總鏈接
- 1.技術博客匯總
- 2.開源項目匯總
- 3.生活博客匯總
- 4.喜馬拉雅音頻匯總
- 5.其他匯總
02.關于我的博客
- github:https://github.com/yangchong211
- 知乎:https://www.zhihu.com/people/yczbj/activities
- 簡書:http://www.jianshu.com/u/b7b2c6ed9284
- csdn:http://my.csdn.net/m0_37700275
- 喜馬拉雅聽書:http://www.ximalaya.com/zhubo/71989305/
- 開源中國:https://my.oschina.net/zbj1618/blog
- 泡在網上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
- 郵箱:yangchong211@163.com
- 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100-?239.headeruserinfo.3.dT4bcV
- segmentfault頭條:https://segmentfault.com/u/xiangjianyu/articles
- 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e
線程池封裝庫GitHub鏈接:https://github.com/yangchong211/YCThreadPool
轉載于:https://www.cnblogs.com/yc211/p/10916873.html
總結
以上是生活随笔為你收集整理的Android线程池封装库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于 Storyboard 多种方式的页
- 下一篇: Linux之自动化部署