Android线程和线程池


Android线程和线程池_第1张图片
image.png

主线程与子线程

  1. 主线程:主线程主要处理UI交互,需要在任何时候都有较高的响应速度,否则界面会产生卡顿。主线程中不能执行耗时任务,否则会出现ANR。主要作用是运行四大组件,处理它们和用户的交互
  2. 子线程:也叫工作线程,除主线程以外的线程都叫子线程。主要用来处理耗时任务,如网络请求、I/O。

Android中的线程形态

Android中除了传统的Thread之外,还包含了AsyncTask、HandlerThread以及IntentService,这三者底层实现也是Thread,但它们有特殊的形态和各自的优缺点。

  1. AsyncTask
  • 一种轻量级的异步任务类,可以在线程池中执行后台任务,然后把进度和结果传递给主线程,并在主线程中更新UI。AsyncTask内部封装了Thread和Handler。
  • AsyncTask是一个抽象泛型类,提供了三个参数Params、Progress和Result,Params表示参数,Progress表示后台任务执行的进度类型,Result表示返回结果的类型。
public abstract class AsyncTask 
  • 四个核心方法:onPreExecute=异步任务执行之前调用,可做一些准备工作(主线程)、doInBackground=用于执行异步任务(线程池),在此方法中调用publishProgress可以更新任务进度onProgressUpdate=后台任务进度发生改变会调用(主线程)、onPostExecute=异步任务执行完成之后,该方法被调用(主线程)
  • 除了上面的四个方法,AsyncTask还提供了onCancelled方法(主线程),异步任务取消时,onCancelled会被调用,这个时候onPostExecute不会被调用。
  • AsyncTask使用过程中有几个限制:AsyncTask必须在主线程中创建和加载,execute方法也要在主线程中调用,execute方法只能调用一次,不然会报错。不要在程序中直接调用上面四个核心方法。
  • version < Android1.6:串行执行任务,Android1.6 <= version < Android3.0:采用线程池并行执行任务,version >= Android3.0:线程池串行执行任务,不过仍可通过executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, xxx)指定并发线程池来并行执行任务
  • AsyncTask原理分析:1、AsyncTask的构造方法中会初始化一个sHandler:InternalHandler对象,还会初始化一个mWorker:WorkerRunnable对象(执行doInBackgroud,并且把结果发送个sHandler),还有会用mWorker初始化mFuture:FutureTask对象(可取消、可查询任务是否完成,可获取任务结果)。2、execute方法会默认使用sDefaultExecute(串行线程池)来调用executeOnExecutor方法,这个方法中会调用onPreExecute,并且会把mFuture作为一个Runnable(任务)插入线程池的队列mTask。3、如果此时没有active的AsyncTask任务,就会调用scheduleNext来执行队列中的下一个AsyncTask,直到所有任务被执行完为止。4、mFuture任务执行完成后会发送消息给sHandler对象,sHandler处理消息时调用onPostExecute把结果传递给主线程处理
  1. HandlerThread
  • 继承自Thread,可以使用Handler的Thread
  • 在run方法中通过Looper.prepare初始化Looper,并且通过Looper.loop方法开启消息循环。这样就允许在HandlerThread中使用Handler了。
  • 普通Thread在run方法中执行耗时任务。而HandlerThread在run中开启消息循环,外界需要通过Handler发送消息通知HandlerThread执行一个具体任务。
  • 由于HandlerThread方法中调用Looper.loop方法,是一个死循环,当不需要再使用HandlerThread时,通过quit或quitSafety方法终止线程执行。
  1. IntentService
  • 是一种特殊的Service,继承Service的抽象类,抽象方法是onHandleIntent。正常的Service运行在主线程,所以不能执行耗时任务,而IntentService的任务是放在HandlerThread中执行,因此可以执行耗时任务。并且IntentService是四大组件,所以相对于一般线程来说,不易被系统杀死。
  • 在onCreate方法中,创建一个HandlerThread线程,然后用该线程的Looper构造一个Handler(即该Handler是在HandlerThread线程中处理消息)。
  • 每次启动IntentService(startService),它的onStartCommand方法会被调用,onStartCommand会调用onStart方法,onStart方法中会把Intent作为消息参数,发送一个msg给Handler处理,而Handler处理中会调用onHandleIntent方法(运行在在HandlerThread线程中)。
  • Handler处理消息后还会调用stopSelf(msg.arg1)方法结束IntentService,如果目前只存在一个后台任务,那么执行完后stopSelf直接停止服务,如果有多个后台任务,那么当onHandleIntent执行完最后一个任务时,stopSelf才会停止服务。
  • onHandleIntent执行多个后台任务,是按照外界发起的顺序一次执行。

Android中的线程池

  1. 线程池的优点
  • 可以复用线程池中的线程,减少创建和销毁线程带来的开销
  • 有效控制线程池中最大并发数,避免线程之间相互抢占资源导致阻塞现象
  • 对线程进行管理,提供定时和周期执行功能
  1. ThreadPoolExecutor
    ThreadPoolExecutor的继承关系如下:
Executor interface
ExecutorService interface
AbstractExecutorService abstract class
ThreadPoolExecutor class

构造方法如下:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue workQueue,
                            ThreadFactory threadFactory,
                            RejectedExecutionHandler handler) {
      if (corePoolSize < 0 ||
          maximumPoolSize <= 0 ||
          maximumPoolSize < corePoolSize ||
          keepAliveTime < 0)
          throw new IllegalArgumentException();
      if (workQueue == null || threadFactory == null || handler == null)
          throw new NullPointerException();
      this.corePoolSize = corePoolSize;
      this.maximumPoolSize = maximumPoolSize;
      this.workQueue = workQueue;
      this.keepAliveTime = unit.toNanos(keepAliveTime);
      this.threadFactory = threadFactory;
      this.handler = handler;
  }

构造方法中的参数解释:

  • corePoolSize:核心线程数,核心线程在线程池中能够一直存活,及时处于闲置状态。除非把allowCoreThreadTimeOut设置为true,那么当核心线程闲置超过一定时间,就会被终止。
  • maximumPoolSize:线程池能容纳的最大线程数,当线程数达到这个值,后续的任务将会被阻塞。
  • keepAliveTime:线程闲置超时时间,正常情况下,非核心线程闲置超过这个时间会被回收,当设置了allowCoreThreadTimeOut,那么该参数对核心线程也生效。
  • unit:keepAliveTime对应的单位,TimeUnit中取值
  • workQueue:线程池中的任务队列,通过线程池的execute方法提交的Runnable都会存储在此。
  • threadFactory:线程工厂,为线程池提供创建线程的功能,是个接口,只有一个方法:Thread newThread(Runnable r)
  • handler:不常用参数,是RejectedExecutionHandler类型,当线程池无法执行新任务时(任务队列已满),这是会调用handler的rejectedExecution来通知调用者,默认情况会抛出一个异常RejectedExecutionException

ThreadPoolExecutor执行逻辑如下:

1. 线程池线程数量未达到核心线程数,直接启动核心线程执行任务
2. 如果达到或超过核心线程数,会插到任务对队列中排队等待执行
3. 任务队列已满,如果线程数量未达到最大线程数,则会启动非核心线程执行任务
4. 如果达到最大线程数,就会拒绝新任务,会调用RejectedExecutionHandler的rejectedExecution来通知调用者
  1. 线程池分类
    主要介绍四种常见的线程池,都直接或间接配置ThreadPoolExecutor实现自己的功能。
  • FixedThreadPool:线程数量固定,都是核心线程,任务队列无限大。线程不会被回收,能够快速响应外界请求
  • CachedThreadPool:都是非核心线程,并且非核心线程数量无上限,闲置超时时间为60秒,任务队列为空集合,所有任务都能立刻执行。所有线程处于闲置状态时,就会出现线程池内无线程的情况。
  • ScheduledThreadPool:核心线程固定,非核心线程无上限,主要用来执行定时任务和周期任务。
  • SingleThreadExecutor:只有一个核心线程,所有任务在核心线程中顺序执行,不需要处理线程同步问题。

总结

本文主要介绍了Android中线程存在形式,还有线程池的分类和使用。希望对大家有帮助。

你可能感兴趣的:(Android线程和线程池)