AsyncTask是Android给开发者提供的一个简单轻量级的多线程类,通过它我们可以很容易新建一个线程让在后台做一些耗时的操作(如IO操作、网络访问等),并在这个过程中更新UI。之所以说它轻量级,是因为不需要直接使用Handler、Thread等知识,使用起来比较简单,但也失去了一些灵活性,对于一些复杂的场景处理起来不方便。

如果一个APP进程中同时只创建和运行一个AsyncTask实例,则不会有任何问题。但如果在一个进程中如果有多个AsyncTask任务同时在执行,问题就比较复杂了。下面我们通过例子来看(我们例子是在Android 4中运行的)。

一、测试1(默认多个Task是串行执行的)

1、创建一个默认的app工程

2、创建一个类继承AsyncTask,代码如下

package com.example.asynctaskdemo;

import android.os.AsyncTask;

public class MyAsyncTask extends AsyncTask<String, Void, String>{

	private String name;

	public MyAsyncTask(String name){
this.name = name;
} @Override
protected String doInBackground(String... params) {
System.out.println(name+" is run "+System.currentTimeMillis()+" thread id "+Thread.currentThread().getId());
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
} }

3、在Activity的onCreate方法中使用该Task,代码如下

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); for(int i=1;i<5;i++){
MyAsyncTask task = new MyAsyncTask("task"+i);
task.execute(new String[0]);
}
}

  我们在调试窗口,观察MyAsyncTask打印信息的间隔和顺序。发现这创建的4个任务是串行执行的,并不是并发的。

研究了AsyncTask的实现细节,在创建一个AsyncTask并通过其execute方法启动执行时,AsyncTask并不是创建一个独立的线程去执行。AsyncTask是通过线程池来管理和调度进程中的所有Task的。

在 Android2.3以前的版本(SDK/API 大于等于10的版本)

多个AsyncTask任务是并发执行的,也就是说如果启动多个task,则会并发执行。但并发执行的数量取决于AsyncTask内部的线程池限制数量。如果超过了这个限额,新的任务只能等待。

 在Android 3.0及以后版本(SDK/API 大于等于11的版本)

Google从Android 3.0开始对AsyncTask的调度执行做出了一些变化,对于execute提交的任务,按先后顺序每次只运行一个。也就是说它是按提交的次序,每次只启动一个线程执行一个任务,完成之后再执行第二个任务,也就是相当于只有一个后台线程在执行所提交的任务。上面的例子就验证了这一点。

二、让AsyncTask并发执行

因为默认情况下多个task是串行的,那怎么样让并发执行呢?AsyncTask增加了一个新的接口executeOnExecutor,这个接口允许开发者提供自定义的线程池来运行和调度Thread。我们把上面代码改下:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for(int i=1;i<11;i++){
MyAsyncTask task = new MyAsyncTask("task"+i);
//task.execute(new String[0]);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new String[0]);
}
}

  这里我们使用了executeOnExecutor方法代替了execute方法。并且executeOnExecutor方法的第一个参数是一个预定义的线程池。这时这几个task就可以并发执行了。这时我们观察打印的结果,发现有5个任务并发执行,可以看出有5个不同的线程号,查看AsyncTask的源码,发现并发线程数跟设备的cpu数量是有关的,因此不同的设备上可能看到的结果不完全一致,这点需要注意。只有前面的5个任务执行完后,才会执行后面的,并且通过打印的线程号可以看出,后面执行的任务是重用原来的线程,并没有创建新的线程,这就是线程池的作用。

我们再来改下代码,使用Android提供的另外一个预定义的线程池。代码如下:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for(int i=1;i<11;i++){
MyAsyncTask task = new MyAsyncTask("task"+i);
//task.execute(new String[0]);
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, new String[0]);
}
}

观察打印信息我们可以发现,这和调用execute方法一样,每个任务都是串行执行的。并且这个过程中最多创建了5个新的线程。

三、自定义线程池

我们可以利用java.util.concurrent.Executors中的各种静态方法创建供AsyncTask执行的线程池 ,可以指定线程的数量和调度的方式。其方法很多,我们这里介绍其中两种较为常用的。

1、让每个AsyncTask任务都单独起一个线程执行,也就是说所有的都是并发的。代码如:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
for(int i=1;i<11;i++){
MyAsyncTask task = new MyAsyncTask("task"+i);
task.executeOnExecutor(newCachedThreadPool, new String[0]);
}
}

  通过观察打印可以看出,这多个任务都是并发执行的。

2、创建指定线程数量的线程池,并发数上限就是指定的线程数。但新任务产生,没有空闲的线程,就只能等待。代码如:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
for(int i=1;i<11;i++){
MyAsyncTask task = new MyAsyncTask("task"+i);
task.executeOnExecutor(newFixedThreadPool, new String[0]);
}
}

  通过观察可以看出,有3个线程在并发执行。

总结下,从上面的例子中可以看出,如果一个进程中存在多个TASK需要并发执行的情况,那就需要用到AsyncTask一些更深的知识,需要考虑的问题更多。

Android学习笔记:多个AsyncTask实例的并发问题的更多相关文章

  1. Android 学习笔记多媒体技术之 AsyncTask+实现音频播放...

    PS:今天搞了一下如何实现音频播放...结果被坑了,看书上写的代码是挺简单的,但是有个函数就是死活没看懂,这真是受不了...最后才弄明白,原来是一个实现异步任务的一个类...这个类使用java.uti ...

  2. Android学习笔记-绘制圆形ImageView实例

    现在很多的APP都很喜欢圆形的头像,这里就简单的写个圆形的ImageView~ 第三方圆形ImageView控件: RoundedImageView CircleImageView 实现代码: 自定义 ...

  3. 【转】 Pro Android学习笔记(七四):HTTP服务(8):使用后台线程AsyncTask

    目录(?)[-] 5秒超时异常 AsyncTask 实现AsyncTask抽象类 对AsyncTask的调用 在哪里运行 其他重要method 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注 ...

  4. 【转】 Pro Android学习笔记(九二):AsyncTask(1):AsyncTask类

    文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 在Handler的学习系列中,学习了如何h ...

  5. android学习笔记36——使用原始XML文件

    XML文件 android中使用XML文件,需要开发者手动创建res/xml文件夹. 实例如下: book.xml==> <?xml version="1.0" enc ...

  6. Android学习笔记之JSON数据解析

    转载:Android学习笔记44:JSON数据解析 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,为Web应用开发提供了一种 ...

  7. Pro Android学习笔记 ActionBar(1):Home图标区

     Pro Android学习笔记(四八):ActionBar(1):Home图标区 2013年03月10日 ⁄ 综合 ⁄ 共 3256字 ⁄ 字号 小 中 大 ⁄ 评论关闭 ActionBar在A ...

  8. 【转】 Pro Android学习笔记(七六):服务(1):local和remote

    文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ Android提供服务,服务是运行在后台的 ...

  9. 【转】 Pro Android学习笔记(七五):HTTP服务(9):DownloadManager

    目录(?)[-] 小例子 保存在哪里下载文件信息设置和读取 查看下载状态和取消下载 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件,转载须注明出处:http://blog.csd ...

  10. 【转】 Pro Android学习笔记(五六):配置变化

    目录(?)[-] Activity的destorycreate过程 Fragment的destorycreate过程 onSaveInstanceState saveFragmentInstanceS ...

随机推荐

  1. 深究带PLL的错误复位设计

    PLL复位通常犯的错误 或者是像上一篇文章 FPGA知识大梳理(四)FPGA中的复位系统大汇总  中的图一样,也是错误设计.为何呢?看ALTPLL (Phase-Locked Loop) IP Cor ...

  2. 提供基于Lesktop的IM二次开发,联系QQ:87172811

    提供基于Lesktop的IM二次开发,联系QQ:87172811

  3. 读书笔记:js设计模式

    面向过程编程,面向对象编程和函数式编程> 定义一个类方法1:function Anim(){ } Anim.prototype.start = function(){ .. };Anim.pro ...

  4. How to access the properties of an object in Javascript

    Javascript has three different kinds of properties: named data property, named accessor property and ...

  5. poj2342 Anniversary party【树形dp】

    转载请注明出处,谢谢:http://www.cnblogs.com/KirisameMarisa/p/4316097.html   ---by 墨染之樱花 [题目链接]http://poj.org/p ...

  6. 【转载】Java策略消除if else

    策略(Strategy)模式:又名Policy,它的用意是定义一组算法,把它们一个个封装起来,并且使他们可以相互替换.策略模式可以独立于使用他们的客户端而变化.GOF策略模式静态结构类图如下: 通过上 ...

  7. Light OJ 1104 Birthday Pardo(生日悖论)

    ime Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu   Description Sometime ...

  8. 关于PagedDataSource分页属性与DataSet和DataTable详解

    Asp.net提供了三个功能强大的列表控件:DataGrid.DataList和Repeater控件,但其中只有DataGrid控件提供分页功能.相对DataGrid,DataList和Repeate ...

  9. 搭建zend framework1开发环境

    1.和常规开发大致相同,首先下载zend framework1,下载地址如下 http://www.zendframework.com/downloads/latest 挑选其中一个下载,我下载的是f ...

  10. [LeetCode]题解(python):063-Unique Paths II

    题目来源: https://leetcode.com/problems/unique-paths-ii/ 题意分析: 这题的规则和上一题一样.给一个m×n的矩阵0,1矩阵.0代表可以经过,1代表不可以 ...