Android多线程模型

 
        作为开发者,我们都知道在开发过程中遇到耗时操作那是不可避免的,例如网络请求、文件读写、数据库操作等等。Android是单线程模型,这意味着Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。但是Android在UI操作上也做了时间限制,  Activity  ——> 5s 、BroadcastReceiver / ContentProvider  ——> 10s 、 Service  ——> 20s   ,超过这个时间就会报ANR。所以为了避免ANR,我们会开辟新的线程去做这些操作。对于开辟新线程,如果你还是通过 new Thread 的方式去做,那我觉得应该改变了。先不说这样的方式对内存、资源的消耗有多大,有些机型是对一个应用开辟的线程数量是有限制的,超过了就 over了。所以针对这些情况去了解一下Android中的多线程操作还是非常重要的。
 
Android提供了四种常用的操作多线程的方式,分别是:
  1. Handler+Thread
  2. AsyncTask
  3. ThreadPoolExecutor
  4. IntentService
 

1. Handler+Thread

  Android主线程包含一个消息队列(MessageQueue),该消息队列里面可以存入一系列的Message或Runnable对象。通过一个Handler你可以往这个消息队列发送Message或者Runnable对象,通过Looper负责管理线程的消息队列和消息循环,然后处理这些对象。每次你新创建一个Handle对象,它会绑定于创建它的线程(也就是UI线程)以及该线程的消息队列,从这时起,这个handler就会开始把Message或Runnable对象传递到消息队列中,并在它们出队列的时候执行它们,回调 Handler的handlerMessage() 方法。所以Handler流程中,关键的角色:MessageQueue 、 Looper 、Message/Runnable .

优缺点:

  1. Handler用法简单明了,可以将多个异步任务更新UI的代码放在一起,清晰明了 2. 处理单个异步任务代码略显多

适用范围:

  1. 多个异步任务的更新UI

2. AsyncTask

  AsyncTask通过一个阻塞队列BlockingQuery<Runnable>存储待执行的任务,利用静态线程池THREAD_POOL_EXECUTOR提供一定数量的线程,默认128个。在Android 3.0以前,默认采取的是并行任务执行器,3.0以后改成了默认采用串行任务执行器,通过静态串行任务执行器SERIAL_EXECUTOR控制任务串行执行,循环取出任务交给THREAD_POOL_EXECUTOR中的线程执行,执行完一个,再执行下一个。看一下示例代码:
class DownloadTask extends AsyncTask<Integer, Integer, String> { 
     // AsyncTask<Params, Progress, Result> //后面尖括号内分别是参数 @Override protected void onPreExecute() { //第一个执行方法 super.onPreExecute(); } @Override protected String doInBackground(Integer... params) {
      //第二个执行方法,onPreExecute()执行完后执行return "执行完毕"; } @Override protected void onProgressUpdate(Integer... progress) {
       //显示进度super.onProgressUpdate(progress); } @Override protected void onPostExecute(String result) {
       //doInBackground返回时触发,换句话说,就是doInBackground执行完后触发super.onPostExecute(result); } }

通过示例代码,我们知道AsyncTask重要的几个方法: onPreExecute()  、doInBackground(Integer... params) 、onProgressUpdate(Integer... progress)、onPostExecute(String result) 。这四个方法中onProgressUpdate 默认是不会触发的,需要通过对象调用publishProgress() 方法才被调用。

优缺点:

  1. 处理单个异步任务简单,可以获取到异步任务的进度

  2. 可以通过cancel方法取消还没执行完的AsyncTask

  3. 处理多个异步任务代码显得较多

适用范围:

  1. 单个异步任务的处理

3. ThreadPoolExecutor

  ThreadPoolExecutor提供了一组线程池,可以管理多个线程并行执行。这样一方面减少了每个并行任务独自建立线程的开销,另一方面可以管理多个并发线程的公共资源,从而提高了多线程的效率。所以ThreadPoolExecutor比较适合一组任务的执行。但是我们这里强制不允许使用Executor去创建线程池,而是通过ThreadPoolExcutor的方式,规避资源耗尽的风险。

说明:

1) FixedThreadPool 和 SingleThreadPool : 允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM;
2) CachedThreadPool 和 ScheduledThreadPool : 允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

所以正确方式:(更详细的开发规范,点击这里

int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
int KEEP_ALIVE_TIME = 1;
TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>();
ExecutorService executorService = new ThreadPoolExecutor(NUMBER_OF_CORES, NUMBER_OF_CORES*2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, taskQueue, new BackgroundThreadFactory(), new DefaultRejectedExecutionHandler());

适用范围

1. 批处理任务

4. IntentService

IntentService继承自Service,是一个经过包装的轻量级的Service,用来接收并处理通过Intent传递的异步请求。客户端通过调用startService(Intent)启动一个IntentService,利用一个work线程依次处理顺序过来的请求,处理完成后自动结束Service。避免在BroadcastReceiver#onReceive()中执行耗时操作,如果有耗时操作,应该创建IntentService完成,而不应该在BroadcastReceiver内创建子线程去做。

特点

  1. 一个可以处理异步任务的简单Service

参考:

https://www.jianshu.com/p/2b634a7c49ec

https://www.cnblogs.com/chendu123/p/6081301.html

posted @ 2018-04-13 14:45  Spiderman.L  阅读(364)  评论(0编辑  收藏  举报