線程池ThreadPoolExecutor的優點:
1.重用線程池的線程,可以避免因爲線程的創建和銷燬所帶來的性能開銷。
2.可以控制線程池的線程最大併發數量,避免線程之間因爲互相搶佔資源而造成的阻塞。
3.能夠對線程進行簡單的管理,並提供定時執行以及間隔執行等功能。
首先簡單分析一下ThreadPoolExecutor的構成參數:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable>workQueue,
ThreadFactory threadFactory){
}
corePoolSize
線程池的核心線程數,默認情況下,核心線程會一直在線程池中存活下來,既是是處於閒置狀態,。如果將ThreadPoolExecutor的allowCoreThreadTImeOut屬性設置爲true,超時了核心線程也會被終止,這個時間有 keepAliveTime決定。
maximumPoolSize
線程池容納的最大線程數,當活動的線程數量達到上限後,後續的任務將會阻塞。
keepAliveTime
非核心線程可以閒置的時間,超過這個時間,非核心線程會被回收。如果如果將ThreadPoolExecutor的allowCoreThreadTImeOut屬性設置爲true,核心線程也會回收。
unit
用於指定keepAliveTime的時間單位,只是一個枚舉,常用的有TimeUnit.MILLISECONDS,TimeUnit.SECONDS(秒),TimeUnit.MINUTES(分鐘)
workQueue
線程池中的任務隊列,通過線程池的execute()方法提交的Runnable對象會存儲在這個參數中。
threadFactory
線程工廠,爲線程池創建新的線程,它是一個接口,只有一個方法:ThreadnewThread(Runnable)。還有一個方法RejectedExecutionHandler 是當任務隊列已滿或者無法成功執行任務時會調用,報錯的,這裏不再單獨介紹。
ThreadPoolExecutor會遵循以下原則:
1)如果線程池的線程數量沒有達到核心線程的數量,會直接啓動一個核心線程去執行任務。
2)如果線程池的線程數量已經達到或者超過核心線程池的數量,那麼任務會被插到任務隊列中排隊執行。
3)如果在步驟2中任務沒有插入到任務隊列中,說明任務隊列已經排滿,如果線程池中的線程數量沒有達到最大線程數量,會啓動一個非核心線程來執行任務。
4)如果步驟3中的線程池中的線程數量已經達到最大值,就會拒絕執行。
ThreadPoolExecutor在AsyncTask的源碼中有具體提下:
private static final int CPU_COUNT =Runtime.getRuntime().availableProcessors();
private static final int COPE_POOL_SIZE =CPU_COUNT+1;
private static final int MAXIMUM_POOL_SIZE =CPU_COUNT*2+1;
private static final int KEEP_ALIVE =1;
private static final ThreadFactory mThreadFactory = new ThreadFactory() {
private final AtomicInteger mInteger = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r,"AsyncTask #"+mInteger.getAndIncrement());
}
};
private static final BlockingDeque<Runnable> mWorkQueue = new LinkedBlockingDeque<>(128);
public static final Executor threadPoolExector = new ThreadPoolExecutor(COPE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE, TimeUnit.SECONDS
,mWorkQueue,mThreadFactory);
ThreadPoolExecutor的分類
1.FixedThreadPool
通過newFixedThreadPool方法來創建。它是一種線程數量固定的線程池,只有核心線程,線程處於空閒狀態不會回收,除非線程池關閉。並且該線程池內的核心線程沒有超時限制,任務隊列也沒有限制;
public static ExecutorService newFixedThreadPool(int threads){
return new ThreadPoolExecutor(threads,threads,0L,TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>());
}
2. CachedThreadPool:
通過newCachedThreadPool方法創建,它是一種線程數量不固定的線程池,它只有沒核心線程,線程數爲Interget.MAX_VALUE,當線程池的線程都處於活動狀態時,線程池會創建新的線程來處理任務,否則會調用空閒線程處理,超時時長爲60秒。它的任務隊列相當於一個空集合,任何任務都會被執行,適合執行量大耗時較少的任務。
public static ExecutorService newCachedThreadPool(){
return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60,TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}
3. ScheduledThreadPool
通過newScheduledThreadPool方法創建,它的核心線程數量是固定的,非核心線程數量是不固定的,非核心線程空閒時立即回收。適合執行定時任務和具有固定週期的重複任務。
public static public static ScheduledExecutorService newScheduledThreadPool(int threads){
return new ScheduledThreadPoolExecutor(threads);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize,Integer.MAX_VALUE,0,TimeUnit.NANOSECONDS,new DelayedWorkQueue());
}
4. SingleThreadPool
通過newSingleThreadPool來創建,線程池中只有一個核心線程,所有的任務都在一個線程中按順序執行,不需要考慮同步的問題。
public static ExecutorService newSingelThreadPool(){
return new ThreadPoolExecutor(1,1,0L,TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>());
}
常規用法實例:
Runnable mRunnable = new Runnable() {
@Override
public void run() {
//TODO
}
};
public void setThreadPool(){
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
fixedThreadPool.execute(mRunnable);
ExecutorService cachedThreadPool =Executors.newCachedThreadPool();
cachedThreadPool.execute(mRunnable);
ScheduledExecutorService scheduledExecutorService =Executors.newScheduledThreadPool(4);
//延時200毫秒執行
scheduledExecutorService.schedule(mRunnable,200,TimeUnit.MILLISECONDS);
//延遲10毫秒,每1000毫秒執行一次
scheduledExecutorService.scheduleAtFixedRate(mRunnable,10,1000,TimeUnit.MILLISECONDS);
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
singleThreadPool.execute(mRunnable);
}
提供一種封裝好的ThreadPoolUtil:
public class ThreadPoolUtil {
public final static ThreadPoolExecutor mThreadPoolExecutor;
private final static int corePoolSize = 4;
private final static int KEEP_ALIVE_TIME = 60 * 1000;
private final static String CUSTOM_THREAD_NAME = "";
static {
mThreadPoolExecutor = new ThreadPoolExecutor(corePoolSize, Integer.MAX_VALUE, KEEP_ALIVE_TIME,
TimeUnit.SECONDS, new SynchronousQueue<Runnable>(true), new CustomFactory(Thread.NORM_PRIORITY));
}
public static void execute(Runnable runnable) {
mThreadPoolExecutor.execute(runnable);
}
public static void cancle(Runnable runnable) {
mThreadPoolExecutor.remove(runnable);
}
private static class CustomFactory implements ThreadFactory {
int mPriority;
ThreadGroup mThreadGroup;
private AtomicInteger mInteger = new AtomicInteger(1);
public CustomFactory(int normal) {
this.mPriority = normal;
mThreadGroup = Thread.currentThread().getThreadGroup();
}
@Override
public Thread newThread(Runnable r) {
Thread mThread = new Thread(mThreadGroup, r, CUSTOM_THREAD_NAME + mInteger.getAndIncrement(), 0);
mThread.setPriority(mPriority);
return mThread;
}
}