Android学习笔记:多个AsyncTask实例的并发问题
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实例的并发问题的更多相关文章
- Android 学习笔记多媒体技术之 AsyncTask+实现音频播放...
PS:今天搞了一下如何实现音频播放...结果被坑了,看书上写的代码是挺简单的,但是有个函数就是死活没看懂,这真是受不了...最后才弄明白,原来是一个实现异步任务的一个类...这个类使用java.uti ...
- Android学习笔记-绘制圆形ImageView实例
现在很多的APP都很喜欢圆形的头像,这里就简单的写个圆形的ImageView~ 第三方圆形ImageView控件: RoundedImageView CircleImageView 实现代码: 自定义 ...
- 【转】 Pro Android学习笔记(七四):HTTP服务(8):使用后台线程AsyncTask
目录(?)[-] 5秒超时异常 AsyncTask 实现AsyncTask抽象类 对AsyncTask的调用 在哪里运行 其他重要method 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注 ...
- 【转】 Pro Android学习笔记(九二):AsyncTask(1):AsyncTask类
文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 在Handler的学习系列中,学习了如何h ...
- android学习笔记36——使用原始XML文件
XML文件 android中使用XML文件,需要开发者手动创建res/xml文件夹. 实例如下: book.xml==> <?xml version="1.0" enc ...
- Android学习笔记之JSON数据解析
转载:Android学习笔记44:JSON数据解析 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,为Web应用开发提供了一种 ...
- Pro Android学习笔记 ActionBar(1):Home图标区
Pro Android学习笔记(四八):ActionBar(1):Home图标区 2013年03月10日 ⁄ 综合 ⁄ 共 3256字 ⁄ 字号 小 中 大 ⁄ 评论关闭 ActionBar在A ...
- 【转】 Pro Android学习笔记(七六):服务(1):local和remote
文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ Android提供服务,服务是运行在后台的 ...
- 【转】 Pro Android学习笔记(七五):HTTP服务(9):DownloadManager
目录(?)[-] 小例子 保存在哪里下载文件信息设置和读取 查看下载状态和取消下载 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件,转载须注明出处:http://blog.csd ...
- 【转】 Pro Android学习笔记(五六):配置变化
目录(?)[-] Activity的destorycreate过程 Fragment的destorycreate过程 onSaveInstanceState saveFragmentInstanceS ...
随机推荐
- MVC-04 视图(3)
五.Url辅助方法 Url辅助方法与HTML辅助方法很类似,HTML辅助方法用来产生HTML标签,而Url辅助方法则负责用来产生Url网址. @Url.Action("About" ...
- Tensorflow 神经网络
Tensorflow让神经网络自动创造音乐 前几天看到一个有意思的分享,大意是讲如何用Tensorflow教神经网络自动创造音乐.听起来好好玩有木有!作为一个Coldplay死忠粉,第一想法就是自动生 ...
- 帝国cms7.2自定义列表建立tag效果 代码 教程
统计记录:(如:select count(*) as total from phome_ecms_news where classid=1 and checked=1) 注:这句SQL的意思是查找统计 ...
- Android之ListView性能优化
ListView滚动速度优化主要可以应用以下几点方法来实现: 1.使用Adapter提供的convertView convertView是Adapter提供的视图缓存机制,当第一次显示数据的时候,ad ...
- Hibernate Dialect must be explicitly set
在偶然一次运行hibernate测试类的时候,出现如下错误,Exception in thread "main" org.hibernate.HibernateException: ...
- Book of Evil 树双向DFS
Book of Evil Paladin Manao caught the trail of the ancient Book of Evil in a swampy area. This area ...
- 过河(bfs)
Problem 2188 过河I Accept: 112 Submit: 277 Time Limit: 3000 mSec Memory Limit : 32768 KB Proble ...
- Matlab pivotgolf
function scoreout = pivotgolf(course,pivotstrat) % PIVOTGOLF Pivot Pickin' Golf. % Your goal is to u ...
- [译]Stairway to Integration Services Level 9 - Control Flow Task Errors
介绍 在本文中,我们会实验 MaximumErrorCount和ForceExecutioResult 故障容差属性,并且还要学习Control Flow task errors, event han ...
- python切片练习
这块儿没什么难的,细心一点就好 L = [] n = 1 while n <= 99: L.append(n) n = n + 2 print(L) #但是在Python中,代码不是越多越好,而 ...