【发布时间】:2013-12-17 16:57:53
【问题描述】:
我创建了以下 2 个异步任务
public class MyAsynctaskWithDelay extends AsyncTask<String,Void,Void> {
@Override
protected Void doInBackground(String... arg0) {
// TODO Auto-generated method stub
System.out.println(arg0[0] + "before sleeping of AsyctaskWithDelay..");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(arg0[0] + "after sleeping of AsyctaskWithDelay..");
//System.out.println(arg0[0]);
return null;
}
}
与
public class MyAsynctaskWithNoDelayLoop extends AsyncTask<String,Void,Void> {
@Override
protected Void doInBackground(String... arg0) {
// TODO Auto-generated method stub
System.out.println(arg0[0] + " The task with no delay...");
//System.out.println(arg0[0]);
return null;
}
}
然后在主要活动中我做了如下操作:
MyAsynctaskWithDelay asynctask1 = new MyAsynctaskWithDelay();
MyAsynctaskWithDelay asynctask2 = new MyAsynctaskWithDelay();
MyAsynctaskWithNoDelayLoop asynctask3 = new MyAsynctaskWithNoDelayLoop();
MyAsynctaskWithNoDelayLoop asynctask4 = new MyAsynctaskWithNoDelayLoop();
asynctask1.execute("Asynctask 1");
asynctask2.execute("Asynctask 2");
asynctask3.execute("Asynctask 3");
asynctask4.execute("Asynctask 4");
因此根据SerialExecutor的定义,任务应该按照execute方法被调用的顺序执行,后台任务不应该被抢占。
但是,我已经运行了这个应用程序并得到了以下结果。
12-02 09:18:20.526: I/System.out(402): Asynctask 1before sleeping of AsyctaskWithDelay..
12-02 09:18:20.576: I/System.out(402): Asynctask 2before sleeping of AsyctaskWithDelay..
12-02 09:18:20.586: I/System.out(402): Asynctask 3 The task with no delay...
12-02 09:18:20.586: I/System.out(402): Asynctask 4 The task with no delay...
12-02 09:18:30.582: I/System.out(402): Asynctask 1after sleeping of AsyctaskWithDelay..
12-02 09:18:30.703: I/System.out(402): Asynctask 2after sleeping of AsyctaskWithDelay..
很明显,前两个任务在 doinbackground 方法中被抢占了,这显然不是预期的。
请澄清我的疑问,以便我可以回答我自己关于 Asynctask Serialexecutor 工作原理的问题。
如果我们深入研究Android的Serial Executor类的源代码就会发现
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
如果我们看一下execute函数的下面部分写成
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
我们会知道,每次调用执行函数时,它都会创建一个新线程,并在该线程内执行后台任务。这意味着任何长时间运行的后台任务都可以被另一个执行的不同 Asynctask 实例的后台任务抢占。那为什么叫Serial Executor呢。
【问题讨论】:
-
我没有看到你以任何方式使用
SerialExecutor.. -
如您所知,默认执行器是串行执行器
-
我已经解决了一些疑问。由于 SERIAL-EXECUTOR 是一个 final 静态字段,它将被同一个 Asynctask 的所有对象共享。随之而来的是执行函数之前的 Synchronized 关键字。因此它作为一个串行执行器工作。但是,从我的Android应用程序的结果中,我们可以看到一些后台任务正在被抢占...请您解释一下...
-
我明白了。我的 minSDKversion 是 8。我现在已经达到了 14。它工作正常。很抱歉在没有纠正自己的情况下指责 Android 框架......
-
这是我关于 Android Asynctask Internal vis-a-vis Half Sync Half Async 模式的讨论...docs.google.com/document/d/…