因为要写团队的推文所以写了这个,很多东西都参考自《Android开发艺术探索》这本书,姑且当做自己的学习笔记。感觉自己还需要学很多东西,要有自己的东西和思想。
在Android中,线程分为主线程和子线程,主界面用于与用户交互,进行UI的相关操作,而子线程则负责耗时操作。如果在主线程中进行耗时操作,就会使程序无法及时的响应。因此耗时操作必须放在子线程中进行。
1、主线程和子线程
主线程是指进程所有用的线程,在Android中即指进行UI与用户交互的线程就是主线程。因此在Android开发中,需要竟可能的把耗时操作,网络请求访问操作,数据库读取操作等放在子线程,以避免主线程长期处于占用状态以降低用户体验。系统要求网络访问必须在子线程中进行,否则会抛出NetworkOnMainThreadException异常。
2、线程形态
Android中的线程形态有传统的Thread,AsyncTask,HandlerThread和IntentService。
2.1、AsyncTask
AsyncTask封装了Thread和Handler,必须在主线程进行调用,它可以在子线程中执行任务,然后将执行的结果传递给主线程并更新UI。但AsyncTask并不适合执行特别耗时的任务。
2.1.1、参数:
AsyncTask是一个泛型类,提供了三个泛型参数,Params ,Progress 和Result。
- Params表示参数的类型
- Progress表示后台任务的执行进度的类型
- Result表示后台任务返回结果的类型
AsyncTask的声明:
public abstract class Asynctask<Params,Progress,Result>
2.1.2、方法:
AsyncTask提供了一些核心方法:
- onPreExecute() 在主线程中调用用来进行异步任务的准备操作。
- doInBackground(Params …… params) 在执行完onPreExecute()后进行子线程任务时自动调用,Params表示异步任务的输入参数。在方法中可以通过publishProgress更新任务的完成进度,同时在结束调用后会返回结果给onPostExecute()方法。
- onProgressUpdate(Params …… params) 在主线程中用于显示任务进行的进度,在publishProgress()方法中被调用。
- onProgressExecute(Result result) 在主线程中用户获取任务结束后回返的结果,即doInBackground的返回值。
- onCancelled() 在主线程中执行,当异步任务被取消后不会执行onProgressExecute方法而会执行onCancelled方法。
2.1.3、调用:
AsyncTask的使用步骤如下:
1.创建AsyncTask子类,具体实现其核心方法
2.创建子类的实例对象
3.调用execute执行异步线程任务
2.1.4、AsyncTask的限制:
1.必须在主线程加载,即第一次访问AsyncTask必须在主线程,对象必须在主线程创建
2.execute必须在UI线程中调用
3.不能再程序中直接调用onPreExecute(),onPostExecute(),doInBackground和onProgressUpdate方法。
4.一个AsyncTask方法只能使用一次
2.1.5、AsyncTask的工作原理:
- execute方法
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params,Progress,Result>executeOnExecutor(Executor exec, Params...params){
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();
mWorker.mParams=params;
exec.execute(mFuture);
return this;
}
在execute方法中,会检测AsyncTask的当前状态,如果当前为RUNNING或FINISHED状态,系统会抛出异常,当为空闲状态,则置为RUNNING状态。
置为RUNNING状态后会调用onPreExecute方法,同时将参数Params传递给mWorker的mParams。之后调用exec.execute,并传入mFuture,其中exec就是传进来的sDefaultExecutor。
- sDefaultExecutor
sDefaultExecutor是一个串行的线程池,一个进程中的所有的AsyncTask全部在这个串行线程池中排队执行,在executeOnExecute方法中,onPreExecute方法最先执行。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
mTasks代表了SerialExecutor这个串行线程池的任务缓存队列,之后用offer向任务缓存队列中添加了一个任务,调用了r的run方法,r就是传入的mFuture,而mFuture的run方法内部会调用MWorker的call方法,接着调用doInBackground方法,开始执行后台任务。执行结束后会调用scheduleNext方法,执行下一个任务。另外mActive表示了AsyncTask的对象,如果MActive为null,则同样会执行scheduleNext方法。在scheduleNext方法中,若缓存队列不为空,则从队列中取出任务执行。
综上,SerialExecutor的工作是将任务加入缓存队列中,而执行任务的是THREAD_POOL_EXECUTOR。
- THREAD_POOL_EXECUTOR
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
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);
即corePoolSize的CPU数加一,maxumumPoolSize的CPU数二倍加一,存活1s,任务缓存队列为LinkedBlockingQueue。
- postResult方法
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
首先用getHandler方法获取AsyncTask获取内部包含的sHandler,然后发送MESSAGE_POST_RESULT消息。
- sHandler
private static final InternalHandler sHandler = new InternalHandler();
private static class InternalHandler extends Handler {
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;
}
}
}
sHandler是一个静态的Handler对象,为了sHandler能够执行环境从后台切换到主线程,则应使用主线程的Looper,在主线程中创建sHandler。sHandler收到MESSAGE_POST_RESULT后,会调用finish方法。源码如下:
- finish
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
}
else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
调用isCancelled()判断任务是否取消,如果取消则调用 onCancelled(result),否则调用onPostExecute(result)。同时将mStatus设为FINISHED,表示对象执行完毕。
2.2、HandlerThread
2.2.1、简介及实现
HandlerThread继承了Thread,能够使用Handler,实现简单,节省系统资源开销。
实现如下:
HandlerThread thread = new HandlerThread("MyHandlerThread");
thread.start();
mHandler = new Handler(thread.getLooper());
mHandler.post(new Runnable(){...});
2.2.2、源码及分析
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
}
它创建了一个消息队列,外界需要通过Handler的消息通知它执行一个任务,由于HandlerThread的run方法是一个无限循环方法,所以可以通过quit方法终止线程的执行。
2.3、IntentService
IntentService是特殊的Service,继承了Service,因为IntentService是一个抽象类,所以必须创建IntentService的子类才能使用。
同时,IntentService是服务,所以在执行时,优先级较高。
IntentService封装了HandlerThread和Handler。
2.3.1、使用
1.定义IntentService子类,传入线程名称,复写onHandlerIntent()方法。
2.在Manifest.xml中注册
3.在Activity中开启服务
2.3.2、源码分析
- onCreate
在IntentThread被第一次启动时,会调用相应的onCreate方法。具体如下:
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
首先实例化新线程,然后获得工作线程的 Looper,并且构造一个Handler对象mServiceHandler,通过mServiceHandler发送的消息都会在HandlerThread中执行。
- onStartCommand
每次启动IntentService都会调用onStartCommand方法,用于处理每个后台任务的Intent。
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
可以看出在onStartCommand中会调用onStart 方法,在onStart方法中,获得ServiceHandler消息的引用,后将消息包装到msg中,之后发送消息。这个消息会在HandlerThread中被处理。
- ServiceHandler方法
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
IntentService的onHandleIntent方法是一个抽象方法,需要实现,作用是从Intent中区分具体任务并执行,调用执行完任务后,stopSelf会直接停止服务,当存在多个任务时,stopSelf则会在最后一个任务执行完毕后停止服务。
3、线程池
在实际使用中,线程池往往更加放标,和线程相比,线程池性能开销小,可避免因为大量线程抢占资源而堵塞,也更容易管理。
java中线程池的接口是ExecutorService,默认实现是ThreadPoolExecutor。
3.1、ThreadPoolExecutor
ThreadPoolExecutor是线程池的实现,构造方法如下
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
- corePoolSize
核心线程数,核心线程会在线程池中一直存活。若将allowCoreThreadTimeOut设置为true,那么核心线程也将有timepout,会在超时后被杀死。
- maximumPoolSize
最大线程数。
- keepAliveTime
非核心线程限制的超时时长,超过设置时间后非核心线程会被收回,allowCoreThreadTimeOut设置为true后核心线程也会被收回。
unit
时间的参数单位workQueue
任务队列,通过线程池的execute方法提交的Runnable对象储存在其中
- threadFactory
线程工厂,为线程池创建线程
ThreadPoolExecutor在执行线程任务是需满足一定的规则
- 首先使用核心线程,在核心线程不够时才启用新线程
- 当任务书大于核心线程数量,那么会被插入等待队列中
- 如果不能插入等待队列,且线程数量未达到最大线程数,则会开启新线程
- 若无法插入等待队列且无法创建新线程,则请求会被拒绝
3.2、线程池的分类
线程池分为四种不同的功能,分别是FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingkeThreadExecutor。
- FixedThreadPool
通过execute的newFixedThreadPool方法创建,固定大小的线程池,每次提交任务都会创建新的线程,直到池中线程数目达到最大。如果有一个线程异常结束后,会产生一个新的线程补充进去。能够更快地相应外界请求。
具体实现如下:
public static ExecutorSrevice newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(nThread,nThreads,
0L,TimeUnit.MILLISECINDS,
new LinkedBlockingQueue<Runnable>());
}
- CachedThreadPool
一个可以根据需要创建线程的线程池,对于很多短期的异步任务,将有效提高性能,调用execute()将重用已构造的线程,如果没有线程可用,将创造一个新的线程并加入线程池,并移除超过60s未使用的线程。适合执行耗时少的任务。
具体实现如下:
public static ExecutorService newCachedThreadPool(){
reutrn new ThreadPoolExecutor(0,Interger.MAX_VALUE,
60L,TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- ScheduledThreadPool
核心线程有限,非核心线程数无线,创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务的需求。
具体实现如下:
public static ScheduledThreadPool newScheduledThreadPool(int corePoolSize){
reutrn new ScheduledThreadPool(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize,Integer.MAX_VALUE,0,MANOSECONDS,new DelayWorkQueue());
}
- SingkeThreadExecutor
创建单线程池,即线程池中只有一个线程,所有的任务是串行执行,如果池中线程因异常结束,会有一个新的线程来代替。以此保证了任务按提交顺序执行。
具体实现如下:
public static ExecutorService newScheduledThreadExecutor(){
reutrn new FinalizeableDelegatedExecutorService
(new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECINDS,new LinkedBlockingQueue<Runnable>()));
}
参考来源:
《Android开发艺术探索》
https://www.cnblogs.com/absfree/p/5357678.html
https://blog.csdn.net/carson_ho/article/details/53407806