Android开发艺术探索——Android的线程和线程池

这是我在学习过程中总结的知识
目的是希望日后回来看或者需要用的时候可以 一目了然 # 的回顾、巩固、查缺补漏
不追求详细相当于书本的精简版或者说是导读(想看详细的直接对应翻书),但会尽力保证读者都能快速理解和快速使用(随理解加深会总结的更加精简),但必要时会附上一些较详细解释的链接
脚注是空白的:表示还没弄懂的知识,了解后会添加

除了Thread还有其他线程
· AsyncTask:底层用到了线程池和Handler,方便开发者在子线程中更新UI
· IntentService:底层直接用到了线程,内部采用HandlerThread,更方便执行后台任务且不容易被杀死
· HandlerThread:底层直接用到了线程,是一种消息循环的线程,内部可以使用Handler

线程过多时,为了防止一个进程频繁地创建和销毁线程,我们采用线程池来缓存一定数量的线程.线程池来自Java,主要通过Executor来派生特定类型的线程池

11.1 主线程和子线程

  • 主线程:不进行耗时的操作以保证响应速度,主要运行四大组件以及处理它们和用户的交互
  • 子线程:执行耗时任务,如网络请求、I/O操作等

11.2 Android中断的线程形态

11.2.1 AsyncTask

  • 不同的API版本AsyncTask具有不同表现
  • AsyncTask是一种轻量的异步任务类,可更新UI
  • 可以更方便地执行后台任务以及在主线程中访问UI,但还是不能耗时
  • 耗时任务推荐使用线程池

AsyncTask的声明

//Params表示参数的类型、Progress表示后台任务的执行进度类型、Result表示后台任务的返回结果类型
public abstract class AsyncTask<Params,Progress,Result>

AsyncTask的核心方法

(1)onPreExecute,在主线程中执行,在异步任务执行之前会被调用来做准备工作
(2)doInBackground(Params…params),在线程池中运行,用于执行异步任务,然后通过 publishProgress 方法来更新任务进度,publishProgress 调用 onProgressUpdate 方法,再返回计算结果给 onPostExecute
(3)onProgressUpdate(Progress values),在主线程中执行,后台任务执行进度改变时被调用
(4)onPostExecute(Result result)在主线程中执行,在异步任务执行之后,此方法返回后台任务返回值
(5)onCancelled,主线程中执行,当异步任务被取消时,会调用该方法,这时onPostExecute将不会被调用

在书P393中有一个使用AsyncTask的例子,大致思路是

  1. doInBackground 用来执行具体的下载任务并通过 publishProgress 方法来更新下载的进度,同时还要判断下载是否被外界取消了
  2. 下载任务完成后 doInBackground 会返回结果,即下载的总字节数
  3. doInBackground 运行在线程池, onProgressUpdate(随着publishProgress被调用而调用)用于更新界面中的下载进度,运行在主线程
  4. 最后onPostExecute被调用,也是运行在主线程,在界面上提示下载完成信息

AsyncTask是用的条件限制
(1)AsyncTask的类必须在主线程中加载,这在Android4.1以上已经自动完成了
(2)AsyncTask的对象必须在主线程中创建
(3)execute方法必须在UI线程调用
(4)不要在程序中调用 doInBackground 等那4个方法
(5)一个AsyncTask对象只能执行一次(调用一次execute方法)

11.2.2 AsyncTask的工作原理

从它的execute方法开始分析,execute又会调用 executeOnExecutor 方法

一个进程中的所有AsyncTask全部在这个串行的线程池(sDefaultExecutor)中排队执行

在executeOnExecutor方法中,AsyncTask的onPreExecute方法最先执行,然后线程开始执行
从 SerialExecutor 的实现跨越分析AsyncTask的排队执行过程.首先系统把AsyncTask的Params参数封装为FutureTask对象(类似Runnable),然后 SerialExecutor 的execute把FutureTask入队,再通过shceduleNext方法串行的执行下一个AsyncTask任务

AsyncTask中有两个线程池(SerialExecutor 和 THREAD_POOL_EXECUTEO)和一个Handler(InternalHandler)
SerialExecutor用于任务的排队
THREAD_POOL_EXECUTEO用于真正地执行任务
InternalHandler用于将执行环境从线程池切换到主线程

AsyncTask默认是串行执行任务的(Android3.0以上的话),我们可以使用executeOnExecutor的方法来实现并行

11.2.3 HandlerThread

HandlerThread继承了Thread,是一种可以使用Handler的Thread
它的实现是在run方法中通过Looper.prepare来创建消息队列,然后开启消息循环

普通的Thread主要用于在run方法中执行一个耗时任务
HandlerThread在内部创建了消息队列,外界需要通过Handler的消息方式在通知它执行一个具体的任务

11.2.4 IntentService

· 它继承了Service并且它是一个抽象类
· 可执行后台耗时任务,执行后它会自动停止
· 优先级高不容易被杀死
· 它的onCreate方法中封装了Handler和HandlerThread

11.3 Android中的线程池

线程池的好处

  1. 避免因为线程的创建和销毁所带来的性能开销
  2. 有效控制线程池的最大并发数,避免大量线程之间因为互相抢占系统资源而导致的阻塞现象
  3. 提供定时执行以及指定间隔循环执行等功能

线程池的实现为ThreadPoolExecutor
线程池主要分为4类,是通过Executors所提供的工厂方法来得到的

11.3.1 ThreadPoolExecutor

它的构造方法的参数解释
corePoolSize
线程池的核心线程数,默认核心线程一直存活
如果设置allowCoreThreadTimeOut为true,那么核心线程会有超时策略,时间由keepAliveTime指定

maximumPoolSize
可容纳最大线程数

keepAliveTime
非核心线程的超时时长

unit
用于指定keepAliveTime参数的时间单位,TimeUnit.MILLISECONDS、TimeUnit.SECONDS、TimeUnit.MINUTES

workQueue
任务队列,通过线程池的execute方法提交的Runnable对象会存储在这个参数中

threadFactory
线程工厂,为线程池提供创建新线程的功能,它是一个接口,只有一个方法:Thread newThread(Runnable r)

ThreadPoolExecutor执行任务时大致遵循如下规则

  1. 线程池中的线程数量<核心线程数量,则直接执行
  2. 线程池中的线程数量>=核心线程数量,任务被插入到任务队列等待执行
  3. 如果任务队列已满,在不超过线程池规定最大值的条件下,启动一个非核心线程来执行
  4. 已经超过规定最大值,调用RejectedExecutionHandler的rejectedExecutiom来拒绝任务

可以通过查看AsyncTask中的线程池配置来大致了解

11.3.2 线程池的分类

本节介绍Android中最常见的四类具有不同功能特性的线程池,它们都直接或者间接通过配置ThreadPoolExecutor来实现自己的功能特性

1. FixedThreadPool
通过Executors的newFixedThreadPool来创建,
是一种线程固定的线程池,
只有核心线程没有超时机制,
任务队列没有大小限制
更加快速响应外界的请求

2. CachedThreadPool
通过Executors的newCachedThreadPool来创建,
线程数量不定的线程池
只有非核心线程,最大线程数为Integer.MAX_VALUE(相当于任意大)
超时时长为60s
任何任务都会被立即执行
比较适合执行大量的耗时较少的任务

3. ScheduledThreadPool
通过Executors的newScheduledThreadPool来创建,
核心线程数固定
非核心线程数没有限制,闲置时被立即回收
用于执行定时任务和具有固定周期的重复任务

4. SingleThreadPool
通过Executors的newSingleThreadPool来创建,
只有一个核心线程,确保所有任务按顺序执行
不需要处理线程同步问题

Stkcd [股票代码] ShortName [股票简称] Accper [统计截止日期] Typrep [报表类型编码] Indcd [行业代码] Indnme [行业名称] Source [公告来源] F060101B [净利润现金净含量] F060101C [净利润现金净含量TTM] F060201B [营业收入现金含量] F060201C [营业收入现金含量TTM] F060301B [营业收入现金净含量] F060301C [营业收入现金净含量TTM] F060401B [营业利润现金净含量] F060401C [营业利润现金净含量TTM] F060901B [筹资活动债权人现金净流量] F060901C [筹资活动债权人现金净流量TTM] F061001B [筹资活动股东现金净流量] F061001C [筹资活动股东现金净流量TTM] F061201B [折旧摊销] F061201C [折旧摊销TTM] F061301B [公司现金流1] F061302B [公司现金流2] F061301C [公司现金流TTM1] F061302C [公司现金流TTM2] F061401B [股权现金流1] F061402B [股权现金流2] F061401C [股权现金流TTM1] F061402C [股权现金流TTM2] F061501B [公司自由现金流(原有)] F061601B [股权自由现金流(原有)] F061701B [全部现金回收率] F061801B [营运指数] F061901B [资本支出与折旧摊销比] F062001B [现金适合比率] F062101B [现金再投资比率] F062201B [现金满足投资比率] F062301B [股权自由现金流] F062401B [企业自由现金流] Indcd1 [行业代码1] Indnme1 [行业名称1] 季度数据,所有沪深北上市公司的 分别包含excel、dta数据文件格式及其说明,便于不同软件工具对数据的分析应用 数据来源:基于上市公司年报及公告数据整理,或相关证券交易所、各部委、省、市数据 数据范围:基于沪深北证上市公司 A股(主板、中小企业板、创业板、科创板等)数据整理计算
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值