
Android应用开发是一种多线程编程,Android中的线程概念源于Java,所以线程的用法也直接用的是Java的。最简单的方法是直接new Thread一个线程出来操作,但从性能优化的角度来说并不推荐这种操作,建议使用线程池以减少线程的创建和销毁时的系统开销。而这一理念在Android的各种框架中也得到体现,如果看源码的话会发现框架内部涉及到线程的地方基本都会用到线程池。
说到线程池肯定要说一下ThreadPoolExecutor类,这个类在创建时可以通过不同的参数配置出不同需求的线程池。构造器定义如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
- corePoolSize:定义核心线程池的大小。就是能容纳多少个线程,这些线程在执行完任务后不会被销毁,以便反复使用。
- maximumPoolSize:定义线程池的最大容量。当核心线程池满了后还能扩充出多少新的线程出来。
- keepAliveTime:非核心线程的空闲时长,超过这个时长就销毁。
- TimeUnit:keepAliveTime的时间单位。
- workQueue:线程队列,核心线程满了以后新提交的任务会在这个队列里排队,线程队列又分为直接提交队列、有界任务队列、无界任务队列、优先任务队列几种。
- threadFactory:线程的创建工厂,主要是定义线程的创建方法,这个参数需要传入一个实现了ThreadFactory接口的对象。
当线程池创建成功后可以通过execute方法把线程对象提交给线程池。ThreadPoolExecutor会创建新的线程并执行线程任务,每次提交都会创建,直到创建的线程数量大于核心线程数时就需要用到线程队列了。ThreadPoolExecutor又根据四种类型的队列有四种不同的线程处理方式。
1.直接提交队列-通过SynchronousQueue实现。这个队列说白了就是一个长度为0的队列,任务放入队列后就立马会新建一个线程并处理,直到线程总数等于maximumPoolSize。
2.有界队列-通过ArrayBlockingQueue实现。ArrayBlockingQueue对象在创建时需要指定队列的容量上限,然后提交的线程任务会被存入这个队列,当队列存满时会创建新的线程并执行队列中的任务,直到线程总数等于maximumPoolSize为止。
3.无界队列-通过LinkedBlockingQueue实现。这种队列的容量是无限(只受内存容量影响)的,也就是说这个队列永远不会满,所以就不会创建新线程而只会等核心线程空闲后执行队列任务。使用这种队列要确保核心线程总能及时处理完任务后再来处理队列中的任务。
4.优先任务队列-通过PriorityBlockingQueue实现。可以视为按线程优先级运行的无界队列。
ThreadPoolExecutor的构造器还可以传入一个类型为RejectedExecutionHandler的参数,这个参数称为“拒绝策略”。会在线程队列存满并且创建的线程总数大于maximumPoolSize时触发,用于在这种情况下还有新提交的任务要怎么处理。主要有四种策略:
- AbortPolicy策略:直接抛异常,不指定时默认使用这个策略。
- CallerRunsPolicy策略:将线程任务放到当前线程执行。
- DiscardOledestPolicy策略:丢充最先加入的线程任务。
- DiscardPolicy策略:丢失提交的线程任务。
此外,Java也根据ThreadPoolExecutor的配置预置了四种不同功能的线程池:FixedThreadPool、CachedThreadPool、SingleThreadExecutor和ScheduledThreadPool。这四种线程池都可以通过Executors的相应静态方法创建。
FixedThreadPool
这种线程池的特点就是线程总数是固定不变的。当提交的线程任务大于线程总数时存入队列中排队处理。通过newFixedThreadPool静态方法创建。
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
CachedThreadPool:
这种线程池的特点是可创建的线程总数不限,且线程池内的线程在空闲时都能被销毁掉以便节省资源。通过newCachedThreadPool的静态方法创建。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
通过源码可以看出核心线程总数为0,而最大线程数是Int类型的最大值,因为没有了核心线程数,所以创建出来的线程都是非核心的,在60秒闲置期过后就能被销毁掉。
SingleThreadExecutor
这个线程池的特点是只有一个线程,所以提交的线程任务都是排队执行,不存在并发执行的情况。可以通过newSingleThreadExecutor方法创建。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
ScheduledThreadPool
是一种特殊的线程池,能够定时和周期性的执行线程任务,当池中的线程数量小于核心线程数时直接创建线程,但不执行,需要通过scheduleAtFixedRate或scheduleWithFixedDelay方法设置执行的周期。如果线程数量大于核心线程数时就把线程任务存到线程队列,等于有空间的核心线程时再执行。通过newScheduledThreadPool静态方法。
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
// ScheduledThreadPoolExecutor继承自ThreadPoolExecutor
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), threadFactory);
}
点击链接加入QQ群聊:https://jq.qq.com/?_wv=1027&k=5z4fzdT
或关注微信公众号:口袋里的安卓
网友评论