如何在安卓中使用线程池(ThreadPoolExecutor)
如何在安卓中使用线程池(ThreadPoolExecutor)
标签(空格分隔): 翻译计划
原文链接地址:Using ThreadPoolExecutor in Android
这篇文章将会覆盖线程池、线程池执行者、和怎么把他们使用到安卓里面。我们将会介绍这些主题,并且会附有许多示例代码。
线程池(Thread Pools)
一个线程池管理者一个工作线程池(线程池确定的个数取决于我们如何实现的)
一个任务队列保持着等待的任务,这些任务将会被线程池中的等待线程执行。生产者把任务添加到队列中,而工作线程作为消费者,只要有空闲的线程准备好执行任务,就从任务队列中取出任务并且消耗掉它。
线程执行者(ThreadPoolExecutor)
ThreadPoolExecutor则使用线程池中的一个线程来执行给定的任务
创建一个线程执行者:
ThreadPoolExecutor executor = ThreadPoolExecutor( int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue
);
这些参数的含义
- 1、corePoolSize
- 线程池中的最小线程个数,最初的线程池个数初始化是0个,但是当我们把任务添加到队列中的时候,一个新的线程将会被创建,如果有空线程,但是线程数低于corePoolSize,那么新的线程将会被继续创建
- 2、maximumPoolSize
- 线程池中允许创建的最大线程个数,如果这个数字超过了corePolSize,并且currentPoolSize>=corePoolSize,那么只有当队列满的时候才会去创建新的工作线程。
- 3、keepAliveTime
- 线程存活时间,当线程数大于核心线程(工作线程),那么非核心线程(多于的空闲线程)将等待新的任务,如果这些线程在该参数定义的时间内没有得到任务去执行,将会被销毁。
- 4、unit
- 线程存活时间keepAliveTime的时间单位
- 5、workQueue
- 工作队列,将会持有持续运行任务,这里将会展现BlockingQueue
安卓和Java中为什么会用到线程池
- 1、这是一个强大的任务执行框架,支持队列中的任务添加,任务取消和任务优先级排序
- 2、它可以减少线程创建的开销,因为他会在线程池中管理所需要的线程
在安卓中使用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);
}
}
创建一个MainThreadExecutor
public class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable runnable) {
handler.post(runnable);
}
}
创建一个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<Runnable>(),
backgroundPriorityThreadFactory
);
// setting the thread pool executor for mForLightWeightBackgroundTasks;
mForLightWeightBackgroundTasks = new ThreadPoolExecutor(
NUMBER_OF_CORES * 2,
NUMBER_OF_CORES * 2,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
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;
}
}
现在在你的代码逻辑中使用吧
/*
* 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.
}
});
}
通过这种方式,我们可以创建不同的线程池来服务于网络任务/IO任务/(后台)耗时任务、还有其他任务。
如何取消任务
当我们取消一个任务的时候,我们需要得到一个Future,而不是直接执行,因此我们需要使用submit,这样将会返回一个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);
如何对一个任务设置优先级
假设一个任务队列中有20个任务,而我们创建的线程池只有四个可用于工作的线程,我们可以基于优先级来执行任务,毕竟我们一次只能执行4个任务。
假设我们需要在队列中首先执行最后一个任务,我们可以为这个线程设置IMMEDIATE优先级,以便于我们在队列中获取新任务的时候,将会执行此任务(因为这个标志的任务具有最高优先级)
要设置任务的优先级,我们需要创建一个线程池执行器
创建枚举优先级
/**
* 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;
}
创建一个优先级线程
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;
}
}
创建一个PriorityThreadPoolExecutor(优先级线程执行者)继承于ThreadPoolExecutor,我们还需要创建一个PriorityFutureTask,实现Comparable<PriorityFutureTask>接口
public class PriorityThreadPoolExecutor extends ThreadPoolExecutor {
public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, 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;
}
/*
* 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();
}
}
}
首先,在DefaultExecutorSupplier,而不是ThreadPoolExecutor中,向一下使用方式使用PriorityThreadPoolExecutor.
public class DefaultExecutorSupplier{
private final PriorityThreadPoolExecutor mForBackgroundTasks;
private DefaultExecutorSupplier() {
mForBackgroundTasks = new PriorityThreadPoolExecutor(
NUMBER_OF_CORES * 2,
NUMBER_OF_CORES * 2,
60L,
TimeUnit.SECONDS,
backgroundPriorityThreadFactory
);
}
}
给一个如何给一个任务设置优先级的例子
/*
* 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.
}
});
}
通过这种方式,我们就可以创建一个具有优先级的任务,上述所有使用方式同样适用于Java Applications
这里给一个我自己封装的安卓网络工作的依赖库Android Networking Library
如果想知道更详细的实现,可以查看DefaultExecutorSupplier.java这个类在Android Networking here.
我希望这些知识对于你有些帮助
感谢您阅读本文。
如果您发现它有用,请务必点击下面的❤推荐这篇文章。
如果想知道更多的关于程序设计方面的知识, follow me and Mindorks ,以便于我们更新新的技术文章的时候会通知到你。
Check out all the Mindorks best articles here.
Also, Let’s become friends on Twitter, Linkedin, Github and Facebook.
当然了最后的这些推荐都是需要翻墙的,这个就需要大家墙一下了哈.这里推荐给大家一个翻墙的网址,需要收费的,但是非常便宜的(最低的套餐一个月15G/1.5元 一年才18(现在搞活动)),可以看一下