title: 安卓中使用ThreadPoolExcutor
date: 2016-07-29 10:14:02
tags:
- android
- 翻譯

這篇文章將涉及到線程池,線程池執行程序,和他們在Android中的使用。
我們將使用很多的利用,詳細的(thoroughly)介紹這些主題。
Thread Pools (線程池)
一個線程池管理一池的工作線程(準確的數量依賴于它的實現方式)。
一個task隊列等待池中的空閑線程執行隊列中的task.Task被生產者加入隊列中,工作線程作為消費者,只要池中有空閑線程在等待新的后臺任務,就會從task隊列中消費任務。
ThreadPoolExcutor
ThreadPoolExcutor 從線程池中的一個線程執行一個給定的task。
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue
);
參數解釋:
- corePoolSize: 線程池中保留線程的最小數目,最開始線程池中沒有線程,但是隨著task被加入隊列,新線程被創建。如果有空閑的線程,但是線程的數目小于corePoolSize,就會創建新的線程。
- maximumPoolSize: 線程池中線程的最大值,如果線程數量超過corePoolSize,線程數量>=corePoolSize,那么只有隊列滿的時候才會創建新的工作線程。
- keepAliveTime: 當線程數量超過corepoolsize,非corepoolsize的空閑線程將等待一個新的task,如果在這個定義的時間參數內沒有等到新的task,該線程將被終止。
- unit: keppAliveTime的時間單位
- workQueue: task隊列,持有runnable task,必須是一個BlockingQueue.
為什么在Android和JAVA應用程序中使用Thread Pool Executor?
- 它是一個強大的任務執行框架,支持任務添加到隊列,任務取消,任務優先級。
- 降低了線程創建的開銷,它在線程池內管理一定數量的線程。
在Android中使用ThreadPoolExcutor
首先,創建一個PriorityThreadFactory:
import android.os.Process;
import java.util.concurrent.ThreadFactory;
/**
* Created by Adam on 2016/7/29.
*/
public class PriorityThreadFactory implements ThreadFactory {
private final int mThreadPrority;
public PriorityThreadFactory(int mThreadPrority) {
this.mThreadPrority = mThreadPrority;
}
@Override
public Thread newThread(final Runnable r) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Process.setThreadPriority(mThreadPrority);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
r.run();
;
}
};
return new Thread(runnable);
}
}
創建一個MainThreadExecutor:
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.Executor;
/**
* Created by Adam on 2016/7/29.
*/
public class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable command) {
handler.post(command);
}
}
創建一個DefaultExecutorSupplier:
import android.os.Process;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by Adam on 2016/7/29.
*/
public class DefaultExecutorSupplier {
/*
*指定線程數量
*/
public static final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
/**
* 后臺任務的線程池
*/
private final ThreadPoolExecutor mForBackgroundTasks;
/**
* 輕量后臺任務的線程池
*/
private final ThreadPoolExecutor mForLightWeightBackgroundTasks;
/**
* 主線程任務的線程池executor
*/
private final Executor mMainThreadExcutor;
private static DefaultExecutorSupplier mInstance;
/**
* 返回DefaultExecutorSupplier的實例
*/
public static DefaultExecutorSupplier getInstance() {
if (mInstance == null) {
synchronized (DefaultExecutorSupplier.class) {
mInstance = new DefaultExecutorSupplier();
}
}
return mInstance;
}
private DefaultExecutorSupplier() {
ThreadFactory backgroundPriorityThreadFactory = new PriorityThreadFactory(Process.THREAD_PRIORITY_BACKGROUND);
mForBackgroundTasks = new ThreadPoolExecutor(
NUMBER_OF_CORES * 2,
NUMBER_OF_CORES * 2,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
backgroundPriorityThreadFactory
);
mForLightWeightBackgroundTasks = new ThreadPoolExecutor(
NUMBER_OF_CORES * 2,
NUMBER_OF_CORES * 2,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
backgroundPriorityThreadFactory
);
mMainThreadExcutor = new MainThreadExecutor();
}
/*
* returns the thread pool executor for background task
*/
public ThreadPoolExecutor forBackgroundTasks() {
return mForBackgroundTasks;
}
/*
* returns the thread pool executor for light weight background task
*/
public ThreadPoolExecutor forLightWeightBackgroundTasks() {
return mForLightWeightBackgroundTasks;
}
/*
* returns the thread pool executor for main thread task
*/
public Executor forMainThreadTasks() {
return mMainThreadExcutor;
}
}
注意:不同線程池的數量依賴于你的需求
現在在你的代碼中這樣使用
/*
* 后臺任務
*/
public void doSomeBackgroundWork() {
DefaultExecutorSupplier.getInstance().forBackgroundTasks()
.execute(new Runnable() {
@Override
public void run() {
// 在這里后臺工作.
}
});
}
/*
* 輕量后臺任務
*/
public void doSomeLightWeightBackgroundWork() {
DefaultExecutorSupplier.getInstance().forLightWeightBackgroundTasks()
.execute(new Runnable() {
@Override
public void run() {
// 在這里做一些輕量后臺工作.
}
});
}
/*
* 主線程任務
*/
public void doSomeMainThreadWork() {
DefaultExecutorSupplier.getInstance().forMainThreadTasks()
.execute(new Runnable() {
@Override
public void run() {
// 做一些中線程工作.
}
});
}
這樣,我們可以為網絡任務,I/O任務,重型的后臺任務和其他任務創建不同的線程池。
怎樣取消一個task?
為了取消一個task,你必須得到task的future。所以,不要使用execute,使用submit,將返回一個future。現在future就可以用來取消task了。
Future future= DefaultExecutorSupplier.getInstance().forBackgroundTasks()
.submit(new Runnable() {
@Override
public void run() {
}
});
future.cancel(true);
如何設置task的優先級?
假設隊列里有20個任務,線程池持有4個線程,我們根據task的優先級處理他們,因為線程池此時同時可處理4個線程。
但是假設我們需要我們最后推進隊列的任務最先執行,我們需要為該任務設置立即的優先當線程從隊列里拿取新任務時。
為了設置任務的優先級,我們需要創建一個線程池executor。
為優先級創建一個枚舉類:
/**
* Created by Adam on 2016/7/29.
*/
public enum Priority {
/**
* 注意:不要在任何情況下改變順序,否則會使排序不準確
*/
/**
* 最低優先級,預加載數據用
*/
LOW,
/**
* 中優先級
*/
MEDIUM,
/**
* 高優先級
*/
HIGH,
/**
* 立即
*/
IMMEDIATE,
}
創建一個PriorityRunnable
public class PriorityRunnable implements Runnable {
private final Priority priority;
public PriorityRunnable(Priority priority) {
this.priority = priority;
}
@Override
public void run() {
}
public Priority getPriority(){
return priority;
}
}
創建一個PriorityThreadPoolExecutor,繼承自ThreadPoolExecutor.我們必須創建PriorityFutureTask,將實現Comparable<PriorityFutureTask>接口。
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by Adam on 2016/7/29.
*/
public class PriorityThreadPoolExecutor extends ThreadPoolExecutor {
public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, new PriorityBlockingQueue<Runnable>(), threadFactory);
}
@Override
public Future<?> submit(Runnable task) {
PriorityFutureTask futureTask = new PriorityFutureTask((PriorityRunnable) task);
execute(futureTask);
return futureTask;
}
private static final class PriorityFutureTask extends FutureTask<PriorityRunnable>
implements Comparable<PriorityFutureTask> {
private final PriorityRunnable priorityRunnable;
public PriorityFutureTask(PriorityRunnable priorityRunnable) {
super(priorityRunnable, null);
this.priorityRunnable = priorityRunnable;
}
@Override
public int compareTo(PriorityFutureTask another) {
Priority p1 = priorityRunnable.getPriority();
Priority p2 = another.priorityRunnable.getPriority();
return p2.ordinal() - p1.ordinal();
}
}
}
首先在DefaultExcutorSupplier,用PriorityThreadPoolExecutor代替ThreadPoolExecutor.
ThreadFactory backgroundPriorityThreadFactory = new PriorityThreadFactory(Process.THREAD_PRIORITY_BACKGROUND);
// mForBackgroundTasks = new ThreadPoolExecutor(
// NUMBER_OF_CORES * 2,
// NUMBER_OF_CORES * 2,
// 60L,
// TimeUnit.SECONDS,
// new LinkedBlockingQueue<Runnable>(),
// backgroundPriorityThreadFactory
//
// );
mForBackgroundTasks=new PriorityThreadPoolExecutor(
NUMBER_OF_CORES * 2,
NUMBER_OF_CORES * 2,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
backgroundPriorityThreadFactory
);
下面的例子演示了如何設置高優先級:
public void doSomeTaskAtHighPriority(){
DefaultExecutorSupplier.getInstance().forBackgroundTasks()
.submit(new PriorityRunnable(Priority.HIGH){
@Override
public void run() {
super.run();
}
});
}