作为开发者,我们都知道在开发过程中遇到耗时操作那是不可避免的,例如网络请求、文件读写、数据库操作等等。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

Android多线程模型的更多相关文章

  1. Android多线程分析之四:MessageQueue的实现

    Android多线程分析之四:MessageQueue的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前面两篇文章<Androi ...

  2. android 多线程概述

    android多线程,一直是一个麻烦的事情,要掌握它的本质,我们需要搞清楚一个问题,linux多线程的本质. 我们这篇文章,来讨论以下的议程: 了解linux的历程,了解android的异步任务机制, ...

  3. 由UI刷新谈到线程安全和Android单线程模型

    1.为什么说invalidate()不能直接在线程中调用? Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在非UI主线程中调用,因为他是违背了单线程模型:A ...

  4. android 多线程

    本章讲述在android开发中,多线程的应用.多线程能够处理耗时的操作并优化程序的性能.本章主要介绍知识点,AsyncTask,Java线程池,ThreadPoolExecutor线程池类.本章案例只 ...

  5. Android多线程分析之五:使用AsyncTask异步下载图像

    Android多线程分析之五:使用AsyncTask异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处 在本系列文章的第一篇<An ...

  6. Android多线程分析之三:Handler,Looper的实现

    Android多线程分析之三:Handler,Looper的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多 ...

  7. Android多线程分析之二:Thread的实现

    Android多线程分析之二:Thread的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处   在前文<Android多线程分析之一 ...

  8. Android多线程分析之一:使用Thread异步下载图像

    Android多线程分析之一:使用Thread异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处   打算整理一下对 Android F ...

  9. 无废话Android之smartimageview使用、android多线程下载、显式意图激活另外一个activity,检查网络是否可用定位到网络的位置、隐式意图激活另外一个activity、隐式意图的配置,自定义隐式意图、在不同activity之间数据传递(5)

    1.smartimageview使用 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&q ...

随机推荐

  1. window JNI_CreateJavaVM启动java程序

    https://blog.csdn.net/earbao/article/details/51889605 #define _CRT_SECURE_NO_WARNINGS 1       #inclu ...

  2. Linux笔记 #08# shell编程从零开始到低配学生管理系统

    先熟悉一下基本语法(运行环境是装git的时候一起装的那个windows下的bash): #!/bin/bash # 实现两个函数 # appendToFile()追加一行到文件 # readFile( ...

  3. Solr基本操作

    /update 使用/update进行索引维护,进入Solr管理界面SolrCore下的Document下: 我们进行更新操作可以用json和xml多种格式,这里以xml格式为例说明.先来看看界面上的 ...

  4. AngularJs 开发遇到的问题,以及解决方案

    1>ng-if 导致 ng-model 失效的问题 比如说下拉联动隐藏显示的时候,多个验证模块,需要使用到ng-if.可以使用 $parent 来解决这个问题 ng-model="$p ...

  5. 利用JQuery Mobile开发web app

    什么是web app web app 是基于web的应用程序,是针对移动设备优化后的web站点,它具有 开发成本低——采用web开发技术,不需要考虑跨平台以及底层适配问题: 升级简单——不需要通知用户 ...

  6. 11: Nginx安装lua支持

    1.1 Nginx 使用lua脚本 注:需要LuaJIT-2.0.4.tar.gz,ngx_devel_kit,lua-nginx-module 1.Nginx安装lua支持 wget -c http ...

  7. [内核驱动] DOS路径转化为NT路径

    转载:http://blog.csdn.net/qq_33504040/article/details/78468278 最近在做一个文件过滤驱动程序,禁止访问指定目录或文件.想要从R3给R0发命令和 ...

  8. Java排序算法之选择排序

    一.算法原理 简单选择排序的基本思想:给定数组:int[] arr={里面n个数据}:第1趟排序,在待排序数据arr[1]~arr[n-1]中选出最小的数据,将它与arrr[0]交换:第2趟,在待排序 ...

  9. 安装jumpserver

    Centos7.5 安装jumpserver 同步服务器时间 #下载 [root@jumpserver ~]# yum install ntpdate -y #同步时间 [root@jumpserve ...

  10. B/S交互过程及tomcat体系结构

    浏览器与服务器交互过程: 1.浏览器根据主机名,如www.baidu.com,去操作系统的hosts文件中查找主机名对应的ip地址. 2.如果查找不到,则会去互联网上的dns服务器上查找主机名对应的i ...