实现方式
新建Thread
Thread实现了Runnable接口,所以新建Thread的时候,可以重写run方法定义线程任务,也可传入Runnable对象。
自定义AsnycTask
一个AsyncTask对象只能执行一次,否则会报错
原理
默认的线程池是类静态对象,直接继承自Excutor,调用execute时,首先将任务Runnable添加到双端队列ArrayDeque种(先进先出),然后从队列中取出执行。所以任务执行是串行的。publishProgress、或者都是通过MainHandler发送到主线程更新。
HandlerThread
继承自Thread,在run方法中初始化了Looper,通过getThreadHandler方法可以获取关联子线程Looper的Handler,所以可以向子线程发送消息。
IntendService
在onCreate的时候,启动一个HandlerThread,初始化一个关联子线程的Handler,给Service发送命令的时候,通过handler给子线程发送消息,最终在子线程中回调onHandleIntent。
总的来说,IntentService是一个异步任务服务,给服务发送任务,最终任务在子线程执行。
线程池
因为线程的创建跟销毁很消耗资源,所以有了线程池的概念。
ThreadPoolExecutor线程池的构造方法参数包括:核心线程数、最大线程数、线程保活时间、阻塞队列(BlockingQueue<Runnable>先进先出存放任务)、线程工厂ThreadFactory。
线程池原理
先看核心线程是否满了,再看等待队列,再看最大线程数
核心线程(corePool):有新任务提交时,首先检查核心线程数,如果核心线程都在工作,而且数量也已经达到最大核心线程数,则不会继续新建核心线程,而会将任务放入等待队列。
等待队列 (workQueue):等待队列用于存储当核心线程都在忙时,继续新增的任务,核心线程在执行完当前任务后,也会去等待队列拉取任务继续执行,这个队列一般是一个线程安全的阻塞队列,它的容量也可以由开发者根据业务来定制。
非核心线程:当等待队列满了,如果当前线程数没有超过最大线程数,则会新建线程执行任务
线程活动保持时间 (keepAliveTime):线程空闲下来之后,保持存活的持续时间,超过这个时间还没有任务执行,该工作线程结束。 饱和策略 (RejectedExecutionHandler):当等待队列已满,线程数也达到最大线程数时,线程池会根据饱和策略来执行后续操作,默认的策略是抛弃要加入的任务。
饱和策略 (RejectedExecutionHandler):当等待队列已满,线程数也达到最大线程数时,线程池会根据饱和策略来执行后续操作,默认的策略是抛弃要加入的任务。
线程池的线程是如何复用的
通过内部类Worker对象,是一个Runnable对象,成员变量Thread关联这个Runnable对象,调用Thread.start时,在worker的run方法里会循环遍历阻塞队列中的任务执行,做到线程的复用执行多个任务
线程池的管理类Excutors
newFixedThreadPool:核心线程跟最大线程一样,组合队列无限大。所以这个方法创建的线程池适合能估算出需要多少核心线程数量的场景。
newSingleThreadExecutor,:有且只有一个线程在工作,适合任务顺序执行,缺点但是不能充分利用CPU多核性能
newCachedThreadPool, 核心线程数0,最大线程数Integer.MAX_VALUE, 线程keepAlive时间60s,用的队列是SynchronousQueue,这种队列本身不会存任务,只做转发,任何线程任务到来都会立刻执行,不需要等待,所以newCachedThreadPool适合执行大量的,轻量级任务。
定时线程池(ScheduledThreadPool):核心线程数量固定、非核心线程数量无限制(闲置时马上回收),执行定时 / 周期性任务