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. QT IP输入框正则表达式(使用QLineEdit的setValidator函数)

    /* ip输入框正则表达式 */ // IP 前3段 QRegExp regExp("[0-9][0-9.][0-9.][.]"); ui->lineEdit_1->s ...

  2. Delphi中的“委托”

    .NET中有委托(Delegate)的概念,其声明形式如下所示:     public delegate void MyDelegate(int aIntParam, string aStringPa ...

  3. C++_template_栈的链式存储及实现

    由于在C++数据结构中的代码不完整,特补全.等日后当工程库调用. 若有疑问,请留言. #include<iostream> using namespace std; template< ...

  4. Modular Inverse(模逆元,扩展欧几里德)

    Modular Inverse Time Limit: 2 Seconds      Memory Limit: 65536 KB The modular modular multiplicative ...

  5. The document "ViewController.xib" could not be opened. Could not read archive.

    The document "ViewController.xib" could not be opened. Could not read archive. Please use ...

  6. 简简单单C#爬虫小计

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net ...

  7. C#中类的运用(Eighth day)

    又到了总结知识的时刻了,今天在云和学院学习了类的运用,下面是今天所学知识的总结: 理论: 类的定义语法: [访问修饰符] class 类名 { 成员;  // 1.通过字段来描述类别信息的变量 ... ...

  8. FFTW程序Demo

    #include<stdio.h> #include<stdlib.h> #include <fftw3.h> #include<string.h> # ...

  9. Failed to fetch URL http://dl-ssl.google.com/android/repository/addons_list-2.xml, reason: Connectio (andriod sdk manager) http://dl-ssl.google.com/android上不去解决方案

    Fetching https://dl-ssl.google.com/android/repository/addons_list-2.xml  Fetched Add-ons List succes ...

  10. Ecmall系统自带的分页功能使用

    在控制器如果没有定义相关模型,直接使用sql语句的话,直接使用如下语句. 即: public $db; $this->db = &db(); //然后开始使用分页类 $sql='sele ...