我們做項目的時候不可避免要接觸到聯網操作或者一些本地的耗時操作,而這些操作不是在主線程裏面進行,會導致ANR異常(卡UI),所以我們要開闢子線程來執行這些操作,然而直接new Thread()會導致線程管理混亂而可能會到導致系統崩潰(如果一些循環操作不斷開啓線程一直new導致內存不足),所以我們有必要建立一個線程管理的工具類來管理這些線程,讓我們的程序更健壯些,更好地去操作和使用線程。。。
直接進入主題-----
安卓裏面有個線程池類ThreadPoolExecutor,這個類的常用構造方法爲
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
RejectedExecutionHandler handler)
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
各個參數所對應的
corePoolSize: 線程池維護線程的最少數量
maximumPoolSize:線程池維護線程的最大數量
keepAliveTime: 線程池維護線程所允許的空閒時間
unit: 線程池維護線程所允許的空閒時間的單位
workQueue: 線程池所使用的緩衝隊列
handler: 線程池對拒絕任務的處理策略
ThreadPoolExecutor 將根據 corePoolSize(最小線程數)和 maximumPoolSize(最大線程數)設置的邊界自動調整池大小。當新任務在方法 execute(java.lang.Runnable) 中提交時,如果運行的線程少於 corePoolSize,則創建新線程來處理請求,即使其他輔助線程是空閒的。如果運行的線程多於corePoolSize 而少於 maximumPoolSize,則將請求放入隊列等待,僅當隊列滿時才創建新線程,如果隊列滿已滿但是線程數小於maximumPoolSize,則開啓臨時線程來執行任務,但是總的線程數不能超過maximumPoolSize,如果等於maximumPoolSize數量則要根據handler處理策略來進行操作線程。如果設置的
corePoolSize 和 maximumPoolSize相同,則創建了固定大小的線程池。如果將 maximumPoolSize 設置爲基本的無界值(如 Integer.MAX_VALUE),則允許池適應任意數量的併發任務。在大多數情況下,核心和最大池大小僅基於構造來設置,不過也可以使用setCorePoolSize(int) 和 setMaximumPoolSize(int) 進行動態更改。
一.首先我們要手動創建一個線程池代理類,代碼貼上-----
public class ThreadPoolProxy {
private ThreadPoolExecutor mExecutor;
private int corePoolSize;
private int maximumPoolSize;
private long keepAliveTime;
public ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long keepAliveTime) {
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.keepAliveTime = keepAliveTime;
}
//雙重鎖機制
public ThreadPoolExecutor initThreadPoolExecutor() {
if (mExecutor == null) {
synchronized (ThreadPoolProxy.class) {
if (mExecutor == null) {
BlockingQueue<Runnable> workQueue = new LinkedBlockingDeque<Runnable>();
ThreadFactory threadFactory = Executors.defaultThreadFactory();
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
mExecutor = new ThreadPoolExecutor(corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
workQueue,
threadFactory,
handler);
}
}
}
return mExecutor;
}}
然後在設置一些執行或移除等對線程操作的方法供調用
//試行任務
public void execute(Runnable task) {
initThreadPoolExecutor();
mExecutor.execute(task);
}
//移除任務
public void remove(Runnable task) {
initThreadPoolExecutor();
mExecutor.remove(task);
}
//提交任務(Future+execute(Runnable task)
public Future<?> submit(Runnable task) {
initThreadPoolExecutor();
return mExecutor.submit(task);
}
二. 建立一個線程池工廠類ThreadPoolFactory,顧名思義,工廠類就可以生產出用戶定製所想要的線程池出來,貼代碼
public class ThreadPoolFactory {
private static ThreadPoolProxy commonThreadPool;
public static final int Common_CORE_POOL_SIZE = 5;
public static final int Common_MAX_POOL_SIZE = 5;
public static final int Common_KEEP_LIVE_TIME = 1; //存活時間
//單例模式
public static ThreadPoolProxy getCommonThreadPool() {
if (commonThreadPool == null) {
synchronized (ThreadPoolFactory.class) {
if (commonThreadPool == null) {
commonThreadPool = new ThreadPoolProxy(Common_CORE_POOL_SIZE, Common_MAX_POOL_SIZE, Common_KEEP_LIVE_TIME);
}
}
}
return commonThreadPool; //返回所要的線程池
}
}
三.建立一個線程池工具類(操作類)來對我們所產生的線程池進行操作
public class ThreadPoolUtils {
//在非UI線程中執行
public static void runTaskInThread(Runnable task){
ThreadPoolFactory.getCommonThreadPool().execute(task);
}
//在UI線程中執行
private static Handler handler = new Handler();
public static void runTaskInUIThread(Runnable task){
handler.post(task);
}
}
在主線程操作我們用handler來分發處理任務。。
對了,我們還可以自定義Toast
//在UI線程
public static void showToastInUIThread(String content){
Toast.makeText(BaseApplication.getContext(), content, Toast.LENGTH_SHORT).show();
}
//在工作線程
public static void showToastInThread(final String content){
ThreadPoolUtils.runTaskInThread(new Runnable() {
@Override
public void run() {
Toast.makeText(BaseApplication.getContext(), content, Toast.LENGTH_SHORT).show();
}
});
}
這樣我們就可以方便的彈出吐司。。。
。。
。