1.线程
1.在操作系统中,线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不能无限制的产生,并且线程的创建和销毁都会有相应的开销。
2.当系统中存在大量的线程时,系统会通过时间片的方式调度每个线程,因此线程不可能做到绝对的并行,除非线程数小于等于CPU的核心数,一般来说这是不可能的。试想一下,如果在一个进程中频繁的创建和销毁线程,这显然不是高效的做法。
3.采用线程池,一个线程池中会缓存一定数量的线程,通过线程池就可以避免因为频繁创建和销毁线程所带来的系统开销。
4.Android中的线程池来源于Java,主要是通过Executor来派生特定类型的线程池,不同种类的线程池又具有各自的特性。
2.线程池的优点
1.重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
2.能有效控制线程池的最大并发数,避免大量的线程之间因相互抢占系统资源而导致的阻塞现象。
3.能够对线程进行简单的管理,并提供定时执行以及指定间隔讯执行等功能。
Android中的线程池的概念来源于Java中的Executor。
Executor是一个接口,里面只有一个 void execute(Runnable command);
方法,真正的实现在ThreadPoolExecutor。ThreadPoolExecutor提供了一系列参数来配置线程池,通过不同的参数可以配置不同的线程池。首先我们来介绍一下ThreadPoolExecutor。
3.ThreadPoolExecutor
下面是它比较常用的构造方法:
public ThreadPoolExecutor( int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize
线程池的核心线程数,默认情况下,核心线程会一直存活(设置了超时机制除外, allowCoreThreadTimeOut属性为true时开启)
maxinmumPoolSize
线程池能容纳的最大线程数,当活动的线程达到这个数值之后,后续新任务会被阻塞
keepAliveTime
非核心线程闲置的超时时长,超过这个时长,非核心线程就会被回收,当allowCoreThreadTimeOut为true时,keepAliveTime同样作用于核心线程。
unit
workQueue
线程池中的任务队列,通过execute方法提交的Runnable对象会存储在这个参数中
threadFactory
线程工厂,为线程池提供创建线程的功能,是个接口,提供Thread newThread(Runnable r)方法
RejectedExecutionHandle
当线程池无法执行新任务时,可能由于线程队列已满或无法成功执行任务,这时候 ThreadPoolExecutor会调用handler的 rejectedExecution的方法,默认会抛出RejectedExecutionException
ThreadPoolExecutor执行任务大致遵循如下规则:
(1)、如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务
(2)、如果线程池中的线程数量已经达到或超过核心线程数量,那么任务会被插入到任务队列中排队等待执行
(3)、如果步骤2中无法将任务插入到任务队列中,往往是因为任务队列已满,这个时候如果线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程来执行任务
(4)、如果步骤3中线程数量达到线程池规定的最大值,线程池会拒绝执行任务,并会调用RejectedExecutionHandler的rejectedExecution方法来通知调用者。
ThreadPeelExecutor的参数配置在AsyncTask中有明显的体现,下面是AsyncTask中线程池的配置情况:
public abstract class AsyncTask<Params, Progress, Result> {
private static final String LOG_TAG = "AsyncTask";
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_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 sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
/** * An {@link Executor} that can be used to execute tasks in parallel. */
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
... ...
}
从上面代码我们可以知道,AsyncTask的THREAD_POOL_EXECUTOR线程池配置:
1.核心线程数等于CPU核心数+1
2.线程池最大线程数为CPU核心数的2倍+1
3.核心线程无超时机制,非核心线程的闲置超时时间为1秒
4.任务队列容量是128
4. 常见的4个线程池
1)FixedThreadPool:线程数量固定的线程池,当所有线程都处于活动状态时,新任务会处于等待状态,只有核心线程并且不会回收(无超时机制),能快速的响应外界请求。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
2)CachedThreadPool:线程数量不定的线程池,最大线程数为Integer.MAX_VALUE(相当于任意大),当所有线程都处于活动状态时,会创建新线程来处理任务;线程池的空闲进程超时时长为60秒,超过就会被回收;任何任务都会被立即执行,适合执行大量的耗时较少的任务。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
3)ScheduledThreadPool:核心线程数量固定,非核心线程数量无限制,非核心线程闲置时会被立刻回收,用于执行定时任务和具有固定周期的重复任务。
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
4)SingleThreadExecutor:只有一个核心线程,所有任务都在这个线程中串行执行,不需要处理线程同步问题
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
摘自《Android开发艺术探索》—任玉刚.