Android 中线程的状态
Android 中线程的状态主要有以下四种:
- Thread
- AsyncTask
- HandlerThread
- IntentService
Thread
Thread 不必说,就是普通的线程,线程的作用主要是执行耗时任务。
AsyncTask
封装了 Handler 和线程池的抽象类。
4 个核心方法:
onPreExecute()
主线程中执行,做一些准备工作。doInBackgound(Params…params)
线程池中执行,执行异步任务。返回结果到onPostExecute
。通过publishProgress
来更新任务进度,publishProgress
会调用onProgressUpdate
方法。onProgressUpdate(Progress…values)
主线程中执行,后台任务执行进度发生变化时被调用。onPostExecute(Result result)
主线程中执行,异步任务执行完后调用,result 参数是doInBackground
的返回值。
使用注意事项:
- AsyncTask 的类必须在主线程加载。
- AsyncTask 的对象必须在主线程中创建。
- execute 方法必须在 UI 线程调用。
- 不要在程序中直接调用以上四个方法。
- 一个 AsyncTask 对象只能 execute 一次。
- Android 3.0 之后,AsyncTask 默认采用一个线程来串行执行任务,可使用 executeOnExecutor 方法来并行执行。
工作原理:
AsyncTask 内有两个线程池(SerialExecutor 和 THREAD_POOL_EXECUTOR),一个 Handler(InternalHandler),其中 SerialExecutor 用于线程池的排队,而 THREAD_POOL_EXECUTOR 用于真正地执行任务。
HandlerThread
封装了 Handler 的 Thread。
IntentService
封装了 HandlerThread 的 Service 抽象类。
Android 中的线程池
线程池的优点:
- 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
- 能有效控制线程池的最大并发数,避免大量的线程之间因为互相抢占系统资源而导致的阻塞现象。
- 能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。
ThreadPoolExecutor
ThreadPoolExecutor 是线程池的实现,其中一个构造函数如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
corePoolSize
线程池的核心线程数,默认核心线程会一直存活,即使处于闲置状态。maximumPoolSize
线程池所能容纳的最大线程数,超过这个数后,新任务将被阻塞。keepAliveTime
非核心线程闲置时的超时时长,超过这个时长,非核心线程将被回收。当 ThreadPoolExecutor 的 allowCoreThreadTimeOut 属性设置为 ture 后,keepAliveTime 同样作用于核心线程。unit
keepAliveTime的时间单位,常用的有TimeUnit.MILLISECONDS,TimeUnit.SECONDS,TimeUnit.MINUTES 等。workQueue
线程池中的任务队列,通过 execute 方法提交的 Runnable 对象会存储在和这个参数中。threadFactory
线程工厂,提供新线程。
ThreadPoolExecutor
执行任务的规则:
如果线程池中线程数量没有达到核心线程数,直接启动一个新线程来执行任务。
如果线程池中的线程数量达到或超过核心线程数,任务会被插到任务队列中排队等待执行。
如果 2 中无法将任务插入队列,这往往是由于队列已满,这个时候如果线程数量没有达到最大值,启动一个新线程来执行。
如果 3 中线程数已经达到最大值,拒绝执行此任务,
ThreadPoolExecutor
调用RejectedExecutionHandler
的rejectedExecution
方法来通知调用者。
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);
它的规格如下:
- 核心线程数 CPU 核心数 + 1
- 最大线程数 CPU 核心数*2 + 1
- 核心线程无超时,非核心线程闲置超时时间 1 秒
- 任务队列容量 128
线程池的分类
FixedThreadPool
线程数量固定,没有非核心线程。更快地相应外界的请求。
ExecutorService service = Executors.newFixedThreadPool(2); public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
CachedThreadPool
线程数量不定,没有核心线程,非核心数量没有限制。主要用于执行大量的耗时较少的任务。
ExecutorService service = Executors.newCachedThreadPool(); public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
ScheduledThreadPool
线程数量不定,核心线程数量固定,非核心数量没有限制。主要用于执行定时任务和具有固定周期的重复任务。
ExecutorService service = Executors.newScheduledThreadPool(2); public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue()); }
SingleThreadExecutor
只有一个线程,不需要处理线程同步。
ExecutorService service = Executors.newSingleThreadExecutor(); public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }