这篇文章将会覆盖到线程池、线程池Executor,以及它们在Android中的使用。通过大量的示例我们将完全覆盖这些主题。
本文是 Using ThreadPoolExecutor in Android 的翻译, 限于个人能力有限如有疑问请查看原文或留言.
线程池
一个线程池管理一池子的工作线程(工作线程的数量依赖于具体的线程池实现)。
一个任务队列容纳等待被线程池中的空闲线程执行的任务。任务被“生产者”添加到队列中,与之对应的工作线程作为消费者的角色消费任务队列中的任务,只要线程池中有空闲的线程等待去执行后台任务。
线程池Executor
线程池executor执行一个线程池中给定的任务。
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue
);
这些参数都是什么含义?
corePoolSize: 线程池中保留的线程的最小数量。
初始情况下线程池中的线程数量为0。但是随着任务被加到队列中,新的线程会被创建。如果在线程池中存在空闲的线程—但是线程的数量小于corePoolSize—那么新的线程会被继续创建。
maximumPoolSize: 线程池中所能容纳的最大线程数量。如果它的数量大于corePoolSize—并且当前的线程数量>= corePoolSize—那么新的工作线程会被继续创建只要任务队列中的任务足够多。
keepAliveTime: 当线程的数量大于corePoolSize,非核心的线程(额外的空闲线程)将会等待新的任务,如果它们在这个参数定义的时间内没有等到一个新的任务,这些线程会被终结。
unit: 参数keepAliveTime的单位
workQueue: 任务队列,它只接收runnable任务。它必须是一个BlockingQueue.
为何要使用线程池在Android或Java程序中
- 它是一个强大的任务处理框架,因为它支持额外的任务保存在队列中,支持任务取消,以及设置任务的优先级。
- 它减小了所需要创建的线程的最大数量,因为它维护了指定数量的线程在它的池子中。
在Android中使用ThreadPoolExecutor
首先,创建一个PriorityThreadFactory:
public class PriorityThreadFactory implements ThreadFactory {
private final int mThreadPriority;
public PriorityThreadFactory(int threadPriority) {
mThreadPriority = threadPriority;
}
@Override
public Thread newThread(final Runnable runnable) {
Runnable wrapperRunnable = new Runnable() {
@Override
public void run() {
try {
Process.setThreadPriority(mThreadPriority);
} catch (Throwable t) {
}
runnable.run();
}
};
return new Thread(wrapperRunnable);
}
}
PriorityThreadFactory.java hosted with ❤ by GitHub
创建一个MainThreadExecutor:
public class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable runnable) {
handler.post(runnable);
}
}
MainThreadExecutor.java hosted with ❤ by GitHub
创建一个DefaultExecutorSupplier:
/*
* Singleton class for default executor supplier
*/
public class DefaultExecutorSupplier{
/*
* Number of cores to decide the number of threads
*/
public static final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
/*
* thread pool executor for background tasks
*/
private final ThreadPoolExecutor mForBackgroundTasks;
/*
* thread pool executor for light weight background tasks
*/
private final ThreadPoolExecutor mForLightWeightBackgroundTasks;
/*
* thread pool executor for main thread tasks
*/
private final Executor mMainThreadExecutor;
/*
* an instance of DefaultExecutorSupplier
*/
private static DefaultExecutorSupplier sInstance;
/*
* returns the instance of DefaultExecutorSupplier
*/
public static DefaultExecutorSupplier getInstance() {
if (sInstance == null) {
synchronized(DefaultExecutorSupplier.class){
sInstance = new DefaultExecutorSupplier();
}
return sInstance;
}
/*
* constructor for DefaultExecutorSupplier
*/
private DefaultExecutorSupplier() {
// setting the thread factory
ThreadFactory backgroundPriorityThreadFactory = new
PriorityThreadFactory(Process.THREAD_PRIORITY_BACKGROUND);
// setting the thread pool executor for mForBackgroundTasks;
mForBackgroundTasks = new ThreadPoolExecutor(
NUMBER_OF_CORES * 2,
NUMBER_OF_CORES * 2,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue(),
backgroundPriorityThreadFactory
);
// setting the thread pool executor for mForLightWeightBackgroundTasks;
mForLightWeightBackgroundTasks = new ThreadPoolExecutor(
NUMBER_OF_CORES * 2,
NUMBER_OF_CORES * 2,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue(),
backgroundPriorityThreadFactory
);
// setting the thread pool executor for mMainThreadExecutor;
mMainThreadExecutor = 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 mMainThreadExecutor;
}
}
DefaultExecutorSupplier.java hosted with ❤ by GitHub
注意:不同的线程池可以维护不同数量的线程,就看你的实际需要了
现在可以像下面这样在你的代码中使用它们:
/*
* Using it for Background Tasks
*/
public void doSomeBackgroundWork(){
DefaultExecutorSupplier.getInstance().forBackgroundTasks()
.execute(new Runnable() {
@Override
public void run() {
// do some background work here.
}
});
}
/*
* Using it for Light-Weight Background Tasks
*/
public void doSomeLightWeightBackgroundWork(){
DefaultExecutorSupplier.getInstance().forLightWeightBackgroundTasks()
.execute(new Runnable() {
@Override
public void run() {
// do some light-weight background work here.
}
});
}
/*
* Using it for MainThread Tasks
*/
public void doSomeMainThreadWork(){
DefaultExecutorSupplier.getInstance().forMainThreadTasks()
.execute(new Runnable() {
@Override
public void run() {
// do some Main Thread work here.
}
});
}
UsingThreadPool.java hosted with ❤ by GitHub
通过这种方式,我们能创建不同的线程池为网络任务,I/O任务,很重的后台任务,以及其它的任务。
如何取消一个任务
要取消一个任务,你需要得到那个任务的future。所以你需要用submit方法而不是execute,它可以返回一 个future对象。你就可以通过这个future对象来取消那个任务。
/*
* Get the future of the task by submitting it to the pool
*/
Future future = DefaultExecutorSupplier.getInstance().forBackgroundTasks()
.submit(new Runnable() {
@Override
public void run() {
// do some background work here.
}
});
/*
* cancelling the task
*/
future.cancel(true);
CancelTask.java hosted with ❤ by GitHub
如何设置任务的优先级
我们假设在一个队列中有20个任务,但是线程池中只有4个线程。我们依据它们的优先级来执行,因为线程池只能同时执行4个任务。
但是假设我们需要让最后一个进入队列中的任务先执行。我们需要给这个任务设置IMMEDIATE优先级,这样就可以让线程取任务时优先取这个任务去执行(因为它的优先级最高)。
要设置任务的优先级,我们需要创建一个线程池executor。
创建一个优先级枚举:
/**
* Priority levels
*/
public enum Priority {
/**
* NOTE: DO NOT CHANGE ORDERING OF THOSE CONSTANTS UNDER ANY CIRCUMSTANCES.
* Doing so will make ordering incorrect.
*/
/**
* Lowest priority level. Used for prefetches of data.
*/
LOW,
/**
* Medium priority level. Used for warming of data that might soon get visible.
*/
MEDIUM,
/**
* Highest priority level. Used for data that are currently visible on screen.
*/
HIGH,
/**
* Highest priority level. Used for data that are required instantly(mainly for emergency).
*/
IMMEDIATE;
}
Priority.java hosted with ❤ by GitHub
创建一个PriorityRunnable:
public class PriorityRunnable implements Runnable {
private final Priority priority;
public PriorityRunnable(Priority priority) {
this.priority = priority;
}
@Override
public void run() {
// nothing to do here.
}
public Priority getPriority() {
return priority;
}
}
PriorityRunnable.java hosted with ❤ by GitHub
创建一个PriorityThreadPoolExecutor,它继承自ThreadPoolExecutor。我们还需要创建一个PriorityFutureTask,它实现了Comparable
public class PriorityThreadPoolExecutor extends ThreadPoolExecutor {
public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit,new PriorityBlockingQueue(), threadFactory);
}
@Override
public Future submit(Runnable task) {
PriorityFutureTask futureTask = new PriorityFutureTask((PriorityRunnable) task);
execute(futureTask);
return futureTask;
}
private static final class PriorityFutureTask extends FutureTask
implements Comparable {
private final PriorityRunnable priorityRunnable;
public PriorityFutureTask(PriorityRunnable priorityRunnable) {
super(priorityRunnable, null);
this.priorityRunnable = priorityRunnable;
}
/*
* compareTo() method is defined in interface java.lang.Comparable and it is used
* to implement natural sorting on java classes. natural sorting means the the sort
* order which naturally applies on object e.g. lexical order for String, numeric
* order for Integer or Sorting employee by there ID etc. most of the java core
* classes including String and Integer implements CompareTo() method and provide
* natural sorting.
*/
@Override
public int compareTo(PriorityFutureTask other) {
Priority p1 = priorityRunnable.getPriority();
Priority p2 = other.priorityRunnable.getPriority();
return p2.ordinal() - p1.ordinal();
}
}
}
PriorityThreadPoolExecutor.java hosted with ❤ by GitHub
首先,在DefaultExecutorSupplier中,我们需要用PriorityThreadPoolExecutor代替ThreadPoolExecutor像下面这个:
public class DefaultExecutorSupplier{
private final PriorityThreadPoolExecutor mForBackgroundTasks;
private DefaultExecutorSupplier() {
mForBackgroundTasks = new PriorityThreadPoolExecutor(
NUMBER_OF_CORES * 2,
NUMBER_OF_CORES * 2,
60L,
TimeUnit.SECONDS,
backgroundPriorityThreadFactory
);
}
}
DefaultExecutorSupplierP.java hosted with ❤ by GitHub
下面是一个例子展示了如果给一个任务设置HIGH优先级:
/*
* do some task at high priority
*/
public void doSomeTaskAtHighPriority(){
DefaultExecutorSupplier.getInstance().forBackgroundTasks()
.submit(new PriorityRunnable(Priority.HIGH) {
@Override
public void run() {
// do some background work here at high priority.
}
});
}
PriorityTask.java hosted with ❤ by GitHub
通过这种方式,一个任务就可以被设置执行地优先级。
上面的实现也适用于任何JAVA程序。
我用了这个线程池实现在Android Networking Library.
想要了解更多实现细节,你可以把 Android Networking here项目中的DefaultExecutorSupplier.java检出看看。
我希望这些讲解能够帮到你。
谢谢阅读这个文章。如果你喜欢这篇文章,那就在下面点一下❤推荐一下吧。
想了解更多的编程知识,你可以关注我,这样我写了新文章时你会得到通知。
来这里看我所有的文章。
谢谢!
你也可以在 Twitter, Linkedin, Github and Facebook找到我。
版权声明
文章版权归本人所有,如需转载需在明显位置处保留作者信息及原文链接 !