简介
1. 线程分类
- 主线程(UI线程) : 处理和界面相关的事情.
- 子线程 : 处理耗时操作.
Android中规定, 只有在主线程中可以进行UI操作, 但是同时, 主线程中不能进行耗时操作,否则会产生ANR,因此耗时操作必须放到子线程中进行处理.
2. Android中多线程技术
- Thread
- AsyncTask : 底层用到了线程池.
封装了线程池和Handler, 主要使用场景是在子线程中更新UI.
- IntentService : 底层使用Thread
内部采用HandlerThread来执行任务,当任务执行完成后IntentService就会自动退出. 从任务执行的角度看,IntentService很像是一个后台线程,其实他是一个Service,正是因为他是服务所以不容易被系统杀死从而保证任务的正常进行.
- HandlerThread : 底层使用Thread
具有消息循环的线程, 内部可以使用Handler.
注意一 : 从Android 3.0 开始如果在子线程中进行网络操作就会产生NetworkOnMainThreadException
AsyncTask
AsyncTask 是一个轻量级异步任务类, AsyncTask 封装了Thread和Handler, 通过AsyncTask可以更加方便地执行后台任务以及在主线程中访问UI, 但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的后台任务来说建议使用线程池.
1. AsyncTask 简单使用
- 创建自定义任务类,继承自AsyncTask.
/**
* 自定义 AsyncTask 类.
* P1 : 输入参数类型
* P2 : 进度类型
* P3 : 返回值类型
*/
private class DownloadTask extends AsyncTask<Integer, Integer, Integer> {
/**
* 1. 主线程
* 2. 执行任务之前执行, 常用来初始化任务,显示UI等.
*/
@Override
protected void onPreExecute() {
Log.d(TAG, "onPreExecute: " + Thread.currentThread().getId());
}
/**
* 1. 子线程
* 2. onPreExecute执行后会立即执行这个方法.任务逻辑就是在这个方法中进行的.
* 3. 可以通过 publicProgress(Progress...) 将任务进度传递到onProgressUpdate.
* 4. 任务结果通过返回值返回, return.传递到onPostExecute.
* @param params P2
* @return P3
*/
@Override
protected Integer doInBackground(Integer... params) {
Log.d(TAG, "doInBackground: " + Thread.currentThread().getId());
for (int i = 0; i < params[0]; i++) {
// 检查任务是否被取消
if (isCancelled()) {
return -1;
}
publishProgress(i);
}
return 0;
}
/**
* 1. 主线程
* 2. publicProgress被调用后会将进度传递到这个方法中.可以在这进行UI更新操作.
* @param values 任务进度.
*/
@Override
protected void onProgressUpdate(Integer... values) {
Log.d(TAG, "onProgressUpdate: " + Thread.currentThread().getId());
Log.d(TAG, "onProgressUpdate: " + values[0]);
}
/**
* 任务执行结束后,就会进入这个回调.
* @param integer 任务结果
*/
@Override
protected void onPostExecute(Integer integer) {
Log.d(TAG, "onPostExecute: " + Thread.currentThread().getId());
Log.d(TAG, "onPostExecute: " + integer);
}
/**
* 任务取消后调用
* @param integer doInBackground 返回值.
*/
@Override
protected void onCancelled(Integer integer) {
super.onCancelled(integer);
}
}
- 启动任务
// 创建并启动任务
new DownloadTask().execute(5);
- 输出
//
D/MainActivity: onPreExecute: 1
//
D/MainActivity: doInBackground: 161
//
D/MainActivity: onProgressUpdate: 1 // 线程id
D/MainActivity: onProgressUpdate: 0 // 进度
D/MainActivity: onProgressUpdate: 1
D/MainActivity: onProgressUpdate: 1 // 进度
D/MainActivity: onProgressUpdate: 1
D/MainActivity: onProgressUpdate: 2 // 进度
D/MainActivity: onProgressUpdate: 1
D/MainActivity: onProgressUpdate: 3 // 进度
D/MainActivity: onProgressUpdate: 1
D/MainActivity: onProgressUpdate: 4 // 进度
//
D/MainActivity: onPostExecute: 1 // 线程id
D/MainActivity: onPostExecute: 0 // 结果
代码中已经有了详细的注释,不进行过多解释,通过Log也证实了.这里说下取消任务
AsyncTask 提供了 cancel(boolean)
取消任务.
- 参数含义:是否立即中断线程执行,true表示立即终止线程,false表示允许任务完成.
- 调用了
cancel()
后onCancelled()
回调会被执行(UI线程),onPostExecute()
不会被执行了. - 调用后
isCancelled
会返回 true. - 建议
onInBackground()
中检查isCancelled
以便尽快结束任务.
2. AsyncTask使用注意
- AsyncTask这个类必须在主线程中进行加载. 在Android 4.1 以后系统自动完成这一过程.Android 6.0 以后可以在子线程中加载
- AsyncTask必须在主线程中创建.
- execute() 必须在UI线程中进行调用.
- 不要在直接调用
onPreExecute(), onPostExecute(), onInBackground() ,onProgressUpdate()
等方法. - 一个AsyncTask 对象 只能调用一次execute方法,如果执行多个任务就创建多个任务.
- Android3.0 以后 ,AsyncTask用一个线程串行执行任务.
3. AsyncTask的工作原理
- 首先分析execute() 方法.由于它是直接调用了executeOnExecutor()因此主要分析一下后者
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
// 调用 : executeOnExecutor
// sDefaultExecutor 是一个串行的线程池Executor.
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
// 检查状态, 此处可用证明为什么一个AsyncTask对象只可以调用一次execute方法.
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING: // 如果任务已经执行,再次执行就会抛出异常.
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED: // 如果任务已经执行完了,再次执行就会抛出异常.
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
// 设置为运行状态.
mStatus = Status.RUNNING;
// 首先调用 onPreExecute, 证实了onPreExecute他回调最先执行.
// onPreExecute在主线程中执行, 这也是AsyncTask的execute()必须在主线程调用的一个的原因.
onPreExecute();
// 保存参数
mWorker.mParams = params;
// 执行线程
// mFuture 是一个Runnable.
exec.execute(mFuture);
return this;
}
代码中已经有了详解的注释这里就不过多的解释了.
-
@MainThread
注解说明这两个方法都必须在主线程中执行,因此execute()
方法必须在主线程中调用. -
if (mStatus != Status.PENDING){...}
中的判断说明了,一个AsyncTask对象只可以调用一次execute()
方法. -
sDefaultExecutor
是一个串行的线程池主要用于任务排队,并不负责任务的实际执行,源码分析如下
// sDefaultExecutor 定义
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
// SERIAL_EXECUTOR : 用于任务排队.
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
// SerialExecutor 串行线程池
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
// 执行Runnable
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
// 调度下一个.
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
// 启动下一个Runnable
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
// 执行任务.
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
// mFuture是一个Runnable
private final FutureTask<Result> mFuture;
-
THREAD_POOL_EXECUTOR
也是一个线程池,负责任务的执行.
// 定义
public static final Executor THREAD_POOL_EXECUTOR;
// 静态加载线程池.
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
-
sHandler
负责线程环境的切换.
// 7.0 代码
// 负责线程切换
private static InternalHandler sHandler;
// 获取Handler
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
// 该类负责实现线程的切换
private static class InternalHandler extends Handler {
// 7.0
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT: // 任务执行结束
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS: // 更新进度.
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
// 任务结束函数
private void finish(Result result) {
if (isCancelled()) {
// 任务被取消
onCancelled(result);
} else {
// 任务正常完成
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
Android 5.0 代码
// 静态加载.
private static final InternalHandler sHandler = new InternalHandler();
private static class InternalHandler extends Handler {
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult result = (AsyncTaskResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
- sHandler 是一个静态的Handler对象,Android 6.0 以前,为了能够将执行环境切换到主线程,这就要求sHandler这个对象必须在主线程中进行创建.
- Android 6.0 以后 sHandler 使用了懒加载,因此,在子线程中也可以进行加载AsyncTask.同时在ActivityThread的main() 方法中也去掉了
AsyncTask.init();
也证实了这一点.
5 总结
- AsyncTask 本质上就是封装了线程池和Handler
- Android 6.0 以后可以在子线程中加载AsyncTask.
HandlerThread
HandlerThread 继承了Thread ,添加加了Looper, 实现方式如下:
- 通过Looper.prepare() 来创建消息队列.
- 通过Looper.loop() 来开启消息循环.
@Override
public void run() {
mTid = Process.myTid();
// 创建消息队列.
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
// 子类实现.
onLooperPrepared();
// 开启运行循环.
Looper.loop();
mTid = -1;
}
- 普通的Thread主要用于进行耗时操作.HandlerThread内部常见了消息队列,外界需要通过Handler的消息方式通知HandlerThread来执行一个任务.由于HandlerThread的run() 是一个无限循环(Looper.loop()),因此当明确不需要时需要主动调用,
quit()
或者quitSafely()
来终止线程的执行.
关于HandlerThread的使用方式参考IntentService源码
IntentService
1. 简介
- IntentService是一种特殊的服务, 他继承自Service并且他是一个抽象类.
- IntentService用于后台耗时任务, 任务执行结束后自动停止.
- 由于它是一个服务因此有着比普通Thread更高的优先级,不容易被系统杀死.因此他适合执行一些优先级较高的后台任务.
2. 工作原理
- IntentService 其实就是封装了 Handler 和 HandlerThread从下面的源码分析中可以看出来.
// 1. Handler
private volatile ServiceHandler mServiceHandler;
// 定义Handler
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// onHandleIntent 这个方法是子类来实现的.
onHandleIntent((Intent)msg.obj);
// 停止当前服务.
stopSelf(msg.arg1);
}
}
// IntentService 的onCreate方法
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
// 创建并启动了HandlerThread.
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
// 保存Looper
mServiceLooper = thread.getLooper();
// 创建Handler , 并且将创建的Handler 和 HandlerThread 的Looper绑定在一起.
mServiceHandler = new ServiceHandler(mServiceLooper);
}
- mServiceHandler就是一个Handler , 并且他的
handleMessage
处理逻辑也十分简单,首先调用onHandleIntent
将结果返给子类处理. 然后调用stopSelf() 来停止服务. - 在onCreate() 方法中创建了一个HandlerThread 并且将Handler和他绑定.
IntentService工作原理如下:
- 在onCreate() 中创建Handler和HandlerThread.并绑定.
- 在
onStart()
中通过Handler 发送消息. - 在 Handler中处理调用onHandleIntent()进行耗时操作.
- 数据通过Intent进行传输.
- 任务执行结束后,后停止服务.
- 在
onDestory()
中退出HandlerThread.
3. 使用
// 定义
public class LocalIntentService extends IntentService{
/**
* 构造方法
*/
public LocalIntentService() {
super("123");
}
@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getStringExtra("task_action");
Log.d(TAG, "onHandleIntent: " + action);
// 延时
SystemClock.sleep(500);
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy: 服务结束");
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
}
Intent intent = new Intent(this, LocalIntentService.class);
intent.putExtra("task_action", "任务 1");
startService(intent);
// 任务二
intent.putExtra("task_action", "任务 2");
startService(intent);
SystemClock.sleep(2000);
// 任务三
intent.putExtra("task_action", "任务 3");
startService(intent);
运行代码发现上述三个任务串行执行,最后会停止服务.
Android中的线程池
Android线程池的概念源自于Java的Executor, Executor 是一个接口,ThreadPoolExecutor 是他的实现类.ThreadPoolExecutor提过了一系列的参数来配置线程池.
Android中的线程池主要分为四类.后面会详细介绍.
1. 线程池的好处
- 重用线程池中的线程, 避免线程的创建和销毁带来的性能开销.
- 能有效的控制线程池的最大并发数, 避免大量线程之间因为抢夺子系统资源而导致的阻塞现象.
- 能够对象成进行简单的管理, 并提供定时执行以及定时间隔循环执行的功能.
2. ThreadPoolExecutor
- 构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory);
- corePoolSize : 线程池的核心线程数,默认情况下核心线程会在线程池中一直存活.如果ThreadPoolExecutor 的 allowCoreThreadTimeOut 属性设置为true, 那么闲置的核心线程会有超时策略,超时时间由keepAliveTime指定.
- maximumPoolSize : 线程池最大的线程数.达到最大值后新任务会阻塞.
- keepAliveTime : 超时时间.
- unit : 超时单位,MILLISECONDS(毫秒),SECONDS(秒), MINUTES(分钟)
- workQueue: 线程池中的任务队列,通过线程池的execute方法提交的Runnable对象会存储在这里.
- threadFactory : 线程工厂, 为线程池提供创建新线程的功能.
除了上面的主要参数以外, ThreadPoolExecuteor还有一个不常用的参数RejectedExecutionHandler handler. 当线程池无法执行新的任务时会调用handler 的rejectedExeception方法来通知调用者, 默认情况下 rejectedExecution 方法会抛出一个rejectedExecutionException异常,具体的可以查看API文档.
-
ThreadPoolExecutor 执行时遵循以下规则:
- 如果线程池中的线程为达到核心线程的数量, 那么会直接启动一个核心线程来执行任务.
- 如果线程池中的线程数量已经达到或者超过核心线程数量, 那么任务会插入任务队列中进行排队.
- 如果过步骤2中无法将任务插入到任务队列,一般是队列已满,这个时候如果线程数量没有达到线程池的最大数量限制,那么会立即启动一个非核心线程来执行任务.
- 如果步骤3中线程数量已经到了线程池规定的最大值, 那么就拒绝执行此任务,ThreadPoolExecutor会调用RejectedExecutionHandler的rejectedExecution() 方法来通知调用者.
AsyncTask中的线程池配置
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
3. Android中的四种线程池.
Android中常用有四种线程池,他们都是直接或者间接配置ThreadPoolExecutor 来实现自己的功能的.
3.1 FixedThreadPool
- 通过Executors 的newFixedThreadPool 方法来创建.
- 线程数量固定.
- 线程处于空闲状态时, 线程也不会被回收,除非线程池关闭了.正是这个原因所以它能够更加快速第响应外界请求.
- 当所有的线程都处于活动状态时, 新任务处于等待状态, 直到有线程空闲.
- 没有超时机制
- 没有任务熟练限制.
newFixedThreadPool方法源码
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
3.2 CachedThreadPool
- 通过Executors的newCachedThreadPool 来创建, 它是一种线程数量不定的线程池,他只有非核心线程并且最大线程数为integer.MAX_VALUE.
- 当线程池中的活动都处于活动状态时,会直接创建新的线程来处理任务.否则就利用空闲线程来处理任务.
- 超时时间是 60s ,线程闲置60s就会被回收.
- 这种线程适合大量的耗时较小的任务.
newCachedThreadPool源码
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
3.3 ScheduledThreadPool
- 通过Executors的newScheduledThreadPool方法来创建.
- 核心线程数是固定的,非核心线程数没有限制.当非核心线程一旦闲置就会被立即回收.
- ScheduledThreadPool主要用来执行定时任务和具有固定周期的重复任务.
newScheduledThreadPool源码
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
3.4 SingleThreadPool
- 通过Executors的newSingleThreadExecutor方法创建.
- 只有一个核心线程,他可以确保所有的任务都在同一个线程中顺序执行.
- 他可以统一所有的外界任务到一个线程中,这样可以避免线程同步问题.
newSingleThreadExecutor源码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
4. 四种常用线程池的用法
private void threadPoolTest() {
// 创建任务
Runnable command = new Runnable() {
@Override
public void run() {
Log.d(TAG, "run: " + Thread.currentThread().getId());
SystemClock.sleep(2000);
}
};
// FixedThreadPool
ExecutorService fixed = Executors.newFixedThreadPool(4);
fixed.execute(command);
// Cached
ExecutorService cached = Executors.newCachedThreadPool();
cached.execute(command);
// Scheduled
ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(4);
// 2000 ms 后执行
scheduled.schedule(command, 2000, TimeUnit.MILLISECONDS);
// 延时 10 后每隔 1000ms 执行一次
scheduled.scheduleAtFixedRate(command, 10, 1000, TimeUnit.MICROSECONDS);
// Single
ExecutorService single = Executors.newSingleThreadExecutor();
single.execute(command);
}