Android中的线程与线程池


Android的线程
一、AsyncTask(线程池 + Handler)
AsyncTask可以在线程池中执行后台任务,然后把执行的进度和最终的进度和结果传输给主线程并在主线程中更新UI。

AsyncTask的四个核心方法:
onPreExecute():执行在当前线程中
doInBackground(Params... params):执行在线程池中
onProgressUpdate(Progress... values):执行在主线程中,与publishProgress(Progress... values)有关
onPostExecute(Result result):执行在主线程中

注意事项:
1、AsyncTask封装了Thread和Handler,该Handler由主线程的Looper构造而成,该过程有AsyncTask.init()完成(包括获取主线程的Looper、构造Handler),在Android4.1及以上版本中,系统会在ActivityThread中自动完成AsyncTask.init过程,在以前的版本中需要手动在主线程中完成。
2、其中AsyncTask必须在主线程中创建,因为AsyncTask一般都会有更新UI的操作,虽然可以在非主线程的AsyncTask,但这样就无法对UI进行更新了,也就失去了AsyncTask的意义了(如onPreExecute()是在非Handler中执行的)
3、一个AsyncTask对象只能执行一次,即只能调用一次的excute方法,否则会报运行时异常(但运行多个AsyncTask对象同时调用excute方法)
因为初始化的时候有下面的一个判断:
if(mStatus!= Status.PENDING) {
   switch(mStatus) {
       caseRUNNING:
           throw newIllegalStateException("Cannot execute task:"
                   +" the task is already running.");
        caseFINISHED:
           throw newIllegalStateException("Cannot execute task:"
                   +" the task has already been executed "
                   +"(a task can be executed only once)");
}

4、Android1.6之前,AsyncTask串行执行任务,1.6-3.0 并行执行,3.0之后默认是串行的,但可以自己指定线程池

二、HandlerThread(Looper + 线程)
继承了Thread,在run方法中开启了Looper,并未外界提供了获取器Looper的方法跟停止运行的的方法qiut(),loop是一个死循环,所以开启了Looper之后,这个线程就不会自动停止了,只能手动停止。
一般的用法是,HandlerThread.start()之后可以用HandlerThread的Looper去构造一个Handler,Handler上的代码将运行在HandlerThread上。

三、IntentService(Service + HandlerThread)
优先级比单纯的线程要高,不容易被系统杀死
在IntentService里面有一个HandlerThread线程,并创建了Handler,在onStart中程序会根据intent对Handler发送消息,在Handler中调用onHandleIntent(Intent)作为线程的真正处理逻辑,执行完onHandleIntent(Intent)后就会通过stopSelf结束服务。
一般的用法是继承IntentService,然后重写onHandleIntent(Intent)就行了
注:由于使用了loop的机制,当同时多个IntenService同时启动,Looper来不及处理时,多个任务会排队逐个执行(就算每个任务都及时执行完了也是可以的,IntenService重新启动就行了)

Handler、MessageQueue、Looper分析
1、程序示例:
Looper.prepare();
Handler handler = new Handler(); //Handler可以根据当前的线程获取它的Looper
Looper.loop();

2、Handler、MessageQueue、Looper功能简介
Handler:是Android消息机制的上层接口,有发送消息和处理消息的功能
MessageQueue:消息队列,采用单链表的数据结构来存储消息列表,对外提供插入和删除的工作
Looper:以无限循环的形式去查找是否有新消息,如果有的话就处理消息,否则就一直等待着

3、ThreadLocal的功能及在Looper中的用法
ThreadLocal:可以在不同线程中互不干扰地存储并提供数据,同过ThreadLocal可以轻松获取每个线程的Looper(它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据)
Looper中ThreadLocal的用法:
开启Looper首先要调用prepare()方法,prepare是一个静态方法,可以说是所有线程公用的,不过prepare中有一个ThreadLocal<Looper>可以用来存储不同线程的Looper,如果是UI线程的话ActivityThread中会直接调用prepareMainLooper,有一个专门的sMainLooper成员存储Looper

4、Handler机制的运行过程:
子线程部分:
handler.sendmessage()在子线程中运行,通过调用MessageQueue的enqueueMessage方法将消息插入messageQueue中,至此,handler的代码还是运行在子线程中的
Looper线程部分:
Looper的代码运行在开启线程中,Looper中创建了一个messageQueue,Looper的loop是一个死循环,会调用MessageQueue的next,next方法也是一个死循环,当有消息的时候会取走一个消息,没有消息的话就处于阻塞的状态
当loop调用next取到一个消息(Message)的时候,Message有一个targe的成员里面存储着发送这个Message的Handler,通过这个Handler就可以调用Handler的dispatchMessage(),dispatchMessage中再通过调用handleMessage(msg)回到真正处理Handler消息的逻辑
注:MessageQueue就相当于一个子线程与Looper线程的桥梁,通过MessageQueue完成了的队列完成了子线程到Looper线程的交接

线程池ThreadPoolExecutor分析
1、线程池作用:
(1)可以避免频繁地创建和销毁线程,减少性能开销
(2)控制线程池的最大并发数,避免大量线程之间相互抢占系统资源而导致阻塞
(3)可以对线程进行简单的管理,定时执行以及指定间隔循环执行等功能

2、Android中常用的四种线程池(通过Executors进行新建)
(1)FixedThreadPool
只有能设置核心线程,没有非核心线程,核心线程没有超时机制,任务队列没有大小限制
(2)CachedThreadPool
没有核心线程,所有任务都交给非核心线程完成,有任务过来就开启一个非核心线程,完成后过60s就结束
(3)ScheduleThreadPool
有固定的核心线程,非核心线程任意数量,非核心线程完成任务后立即结束
(4)SingleThreadPool
只有一个核心线程,没有非核心线程,确保所有任务在同一个线程中顺序执行

3、ThreadPoolExecutor原理分析
构造函数ThreadPoolExecutor只是对成员变量进行的赋值,主要是以下六个成员:
int corePoolSize:核心线程数
int maximumPoolSize:最大线程数,maximumPoolSize - corePoolSize得到非核心线程数
long keepAliveTime:非核心线程的空闲的存或时间(如果设置allowCoreThreadTimeOut为    true,那么keepAliveTime同样作用与核心线程)
TimeUnit unit:时间单位,一般是Time.SECONDS(秒)
BlockingQueue<Runnable> workQueue:任务队列
ThreadFactory threadFactory:线程工厂(ThreadPoolExecutor内部有一个默认的线程工厂)

ThreadPoolExecutor中的关键是Worker及Workers(是一个HashSet<Worker>)
Worker本身是一个Runable,其中有一个线程(是执行它自己的线程),记录了第一个执行Runnable,执行了多少个Runnable等(相当于是一个线程的封装,不过增加一些对线程的控制)
execute的主要任务就是将runnable添加到workQueue当中,当其他线程都处于工作状态并且当前拥有的线程数还小于最大线程数时可以通过addWorker()添加work的数量,并开启相应work的线程
Worker中run方法调用了runWorker(Worker w),在runWorker中会不停地从workQueue中取出任务来进行执行,直到没有任务可取就结束循环,然后调用processWorkerExit(可以进行是否删除worker的处理)
超时机制的猜想:runnWorker中通过getTask循环地获取workQueue中的任务,其中workQueue允许keepAliveTime内阻塞获取,这样就实现了非核心线程空闲时的超时机制
至于核心线程,会结合processWorkerExit来处理,如果是核心线程就重新调用addWorker(null, false)将其添加会workers的队列中

注意:非核心线程是在核心线程在工作中,且任务队列已满的情况下才启动的



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值