大檔案 and 多下載任務的封裝(一)---執行緒池的封裝(ThreadPool,TheadManager)
阿新 • • 發佈:2019-01-30
ThreadManager
前段時間對三級快取機制做了系統的分析,但是對於網路下載的問題還有很多,比如今天遇到的問題,針對一些需要下載大檔案,並且需要進行多執行緒下載的應用來說,(比如,像一些應用商店,軟體的下載和一些累似的多執行緒的下載型別)就需要用到執行緒池,下載就簡單介紹對執行緒池的封裝
一.為什麼要使用執行緒池
根據android單執行緒模式規定,android只允許有一個主執行緒,也就是UI執行緒,一切更新UI的操作必須在UI執行緒中使用,然而對應的一切的耗時操作,只允許在子線稱中執行,所以針對子線稱的下載操作,可以使用執行緒池進行管理,所以封裝執行緒吃對執行緒池管理工具,也是非常實用的。
- 提升效能。建立和消耗物件費時,費CPU資源.
- 防止記憶體過度消耗。控制活動執行緒的數量,防止併發執行緒過多。
- 最大的好處就是,當我們想使用時可以直接新建然後加入執行緒池即可,也可以對執行緒進行復用,當我們不想使用的時候直接就可以把它關閉。
二.為什麼要對執行緒池進行封裝
有的人可能會說, java.util.concurrent.ThreadPoolExecutor;提供了原生的執行緒池,我們為什麼還要對它進行封裝呢?直接使用不就好了,那麼問題來了?
- .ThreadPoolExecutor的使用必須保證一個app中只能擁有一個(也就是必須保證單例模式),否則也無法保證子執行緒的數木
- 封裝是為了更好的管理執行緒,是為了優化程式碼的使用效率,更好的管理程式碼。
三.執行緒池進行封裝
####(一)原理分析
- 首先先看一下ThreadPoolExecutor的引數
/**
下面對執行緒池的方法引數進行解釋,其餘兩個就不解說了,一些引數使用系統預設的即可,
Runtime.getRuntime().availableProcessors();進行設定
對於休息時間,則是為了考慮系統長時間執行而導致的系統發熱現象,
一般情況下可以選擇為0L
**/
ThreadPoolExecutor executor = new ThreadPoolExecutor(
//1.第一個引數:核心的執行緒數,
corePoolSize,
//2.第二個引數,預設使用的最大執行緒數
maximumPoolSize,
//3.執行緒執行時的休眠時間的數值,
keepAliveTime,
//4.執行緒執行時休眠的時間的單位,也就是上一個引數的單位
TimeUnit.SECONDS,
//5.執行緒的佇列
new LinkedBlockingQueue<Runnable>(),
//6.生產執行緒的工廠
Executors.defaultThreadFactory(),
//7.執行緒異常的處理策略
new ThreadPoolExecutor.AbortPolicy()
);
- 因為執行緒池必須保持一個app中只能有一個例項,所以我們使用單例模式,在這裡可以使用懶漢模式
//這裡使用的是ThreadManager類,把它設定稱單例
//而ThreadPool則是在內部類中引用
private static ThreadPool Instance;
//單例模式,獲取執行緒池的例項
public static ThreadPool getInstance(){
if(Instance == null){
synchronized (ThreadPool.class){
if(Instance == null){
int threadCount = Runtime.getRuntime().availableProcessors();
Instance = new ThreadPool(threadCount,threadCount,1L);
}
}
}
return Instance;
}
- 對與執行緒池來說,我們首先應該有一個向執行緒池中新增執行緒的操作
public void execute(Runnable r){
//當ThreadPoolExecutor為null時才新建一個,否則使用原有的。
if(executor == null){
executor = new ThreadPoolExecutor(
corePoolSize,maximumPoolSize,keepAliveTime, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
}
if(executor != null){
//如果不為空,那麼就直接執行此子線稱
executor.execute(r);
}
}
- 當我們對已經開始下載的執行緒突然不想下載了,或者點錯了,那麼就需要取消執行緒
//在這裡我們只需要把執行緒從執行緒池中移除
public void cancel(Runnable r){
if(executor != null){
//雖然已經移除了,但是下載還是正在執行的,所以我們應該在子線稱動態新增取消事件,進行取消
executor.getQueue().remove(r);
}
}
- 為了防止ThreadManager被直接new出物件,所以應該對構造方法進行限制
private Thread<Manager(){
}
四.ThreadManager的使用
//這裡是簡單的使用
Runnable r = new Runnable(){
}
ThreadManager.getInstance().execute(r);
五.程式碼
package com.example.orchid.googleplatstore.manager;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by orchid
* on 16-11-4.
* 執行緒池類的封裝
*
*/
public class ThreadManager {
private static ThreadPool Instance;
//單例模式,獲取執行緒池的例項
public static ThreadPool getInstance(){
if(Instance == null){
synchronized (ThreadPool.class){
if(Instance == null){
int threadCount = Runtime.getRuntime().availableProcessors();
Instance = new ThreadPool(threadCount,threadCount,1L);
}
}
}
return Instance;
}
public static class ThreadPool{
private ThreadPoolExecutor executor;
private int corePoolSize;
private int maximumPoolSize;
private long keepAliveTime;
public ThreadPool(int corePoolSize,int maximumPoolSize,long keepAliveTime) {
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.keepAliveTime = keepAliveTime;
}
public void execute(Runnable r){
if(executor == null){
//執行緒池執行者。
//參1:核心執行緒數;參2:最大執行緒數;參3:執行緒休眠時間;參4:時間單位;參5:執行緒佇列;參6:生產執行緒的工廠;參7:執行緒異常處理策略
executor = new ThreadPoolExecutor(
corePoolSize,maximumPoolSize,keepAliveTime, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
}
if(executor != null){
executor.execute(r);
}
}
//取消執行緒
public void cancel(Runnable r){
if(executor != null){
executor.getQueue().remove(r);
}
}
}
}