《Android开发艺术探索》第十章Android的消息机制、十一章线程和线程池小结

来源:互联网 发布:简单网络机房图片 编辑:程序博客网 时间:2024/05/19 15:25

1. Handler可以将更新UI的操作切换到主线程,MessageQueue采用单链表来存储消息,Looper回无限循环的查找新消息,ThreadLocal可以在每个线程中存储数据,Handler的send被调用时,会调用MessageQueue的enqueueMessage方法将这个消息放入消息队列中,然后Looper发现有新消息就会处理,最终消息中的Runnable或者Handler的handleMessage就会被调用。注意Looper是运行在创建Handler所在的线程中的,这样Handler的业务逻辑就被切换到Looper的线程中了。


2. ThreadLocal的工作原理

1)线程内的全局对象;

private ThreadLocal<Boolean> mBooleanThreadLocal = new ThreadLocal<Boolean>();

mBooleanThreadLocal.set(true);

2)不同线程访问同一个ThreadLocal的get方法,ThreadLocal内部会从各自线程中取出一个数组,然后再从数组中根据当前ThreadLocal的索引去查找出对应的value值;

3)set方法:Thread.currentThread()获取当前线程,通过当前线程得到ThreadLocal.Values对象,内部还有Object[]数组,ThreadLocal的值就存在这个数组中。

ThreadLocal.Values.put(ThreadLocal<?> key, Object value)

4)MessageQueue用单链表实现的,主要包含插入和读取操作,enqueueMessage和next,插入时会根据Message的when属性排序,读取伴随着删除,读不到会阻塞;

5)Looper.prepare会为当前线程创建Looper,并在内部创建MessageQueue,之后调用loop开启循环;Looper的prepareMainLooper方法会把创建的looper保存在进程的静态变量中,作为主线程的looper;quit会直接退出Looper,而quitSafely只是设定一个退出标记,等消息队列处理完毕后才退出;退出后Handler的send方法会返回false;在自线程中如果手动创建了Looper,那么之后应该调用quit终止消息循环,否则自线程一直处于等待状态,退出Looper后子线程也会自动终止。loop方法会调用MessageQueue的next方法来获取信息,获取不到就回阻塞,获取到就调用msg.target.dispatchMessage,将Handler的逻辑在Looper所在的线程中执行;

6)Handler发送消息时会调用MessageQueue的enqueueMessage,处理消息时先调用Message的callback,为空则调用mCallback.handleMessage,再为空则调用handleMessage;Handler的默认无参构造函数会使用当前线程的Looper,也可以传入一个looper。

7)主线程的main的工作:创建Looper,创建ActivityThread,保存Handler,初始化AsyncTask;


3. AsyncTask封装了Thread和Handler,它不适合进行特别耗时的任务,特别耗时的任务建议使用线程池;onPreExecute()在主线程中,doInBackground(Params...)执行异步任务,通过publishProgress更新进度,onProgressUpdate(Progress...)在主线程中更新进度,onPostExecute(Result r)在主线程中异步任务执行后调用,onCancelled方法在主线程中调用;AsyncTask对象的创建和execute调用必须在主线程中,execute只能执行一次,默认的AsyncTask是串行的;exec中调用默认的静态串行线程池sDefaultExecutor执行FutureTask,FutureTask中被传入WorkerRunnable,其中的call方法调用了doInBackground,算出结果后post到主线程的handler中,再调用onPostExecute携带计算结果;


4. HandlerThread

继承了Thread,并且创建了Looper,可以继承onLooperPrepared方法,在它内部创建Handler,接收外界消息在内部处理,用在IntentService中;


5. IntentService

继承了Service,作用很像一个后台进程,但是IntentService是一种服务,它不容易被系统进程杀死而可以尽量保证任务的执行;它封装了HandlerThread和Handler。每次启动IntentService,onStartCommand就会被执行,将Intent包装成Message,再由Handler处理,Handler调用onHandleIntent处理具体Intent,并调用stopSelf(startId)在所有消息都处理完毕后终止服务。每执行一次后台任务就必须重启一次IntentService,IntentService中的Looper是顺序执行后台任务的,onHandleIntent可以根据Intent的不同Action来判断不同的Intent。


6. 线程池

1)优点:可重用避免创建销毁线程的开销;有效控制最大并发数,避免大量线程相互抢占系统资源导致的阻塞现象;可以定时执行或者指定间隔循环执行;

2)ThreadPoolExecutor创建线程池:corePoolSize核心线程数,默认状态下即使空闲也存活,除非设置allowCoreTimeOut;maximumPoolSize最大线程数,达到这个值后续任务将被阻塞;keepAliveTime空闲的最大时长,超过则被回收;unit时间单位;workQueue任务队列,通过线程池的excute提交的Runnable对象列表;threadFactory创建线程的工厂;无法执行新任务时会调用handler的rejectedExecution方法;

3)ThreadPoolExecutor规则:线程池中未达到核心线程数辆,则直接启动一个核心线程执行任务;线程数辆超过核心线程数则任务会排队;如果任务队列已满,则启动非核心线程执行任务;非核心线程也达到最大值,则调用rejectedExecution方法;

4)AsyncTask对THREAD_POOL_EXECUTOR(5.0版本)的配置,核心线程数位CPU数+1,最大线程数为CPU核心数2倍+1,非核心线程1秒超时,任务队列容量128;

5)分类:FixedThreadPool只有核心线程,不会被回收,队列无限制,能快速响应外界请求;CacheThreadPool无限数量的非核心线程,60秒超时,队列容量为空,适合执行大量耗时较少的任务;ScheduledThreadPool有固定的核心线程,无限的非核心线程,空闲时间为0,适合执行定时任务和有固定周期的重复任务,调用scheduleAtFixedRate;SingleThreadExecutor只有一个核心线程,无限队列,将所有任务变成串行处理。

0 0