欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

AsyncTask的运行与Executor androidAsyncTaskExecutor

程序员文章站 2022-04-20 09:02:12
...

帮同事看一个问题: 工程下面同时触发两个的AsyncTask, 预期可以同时执行, 但实际结果它们是顺序执行的.

 

思不得解, 百度一把, 看到有人问怎样控制多AsyncTask的运行优先级, 然后有人回复了一行代码:

AsyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, null);

虽然代码完全没有解决问题, 但是看得出, 这里有一些并发设计相关的东西AsyncTask.SERIAL_EXECUTOR. 它是一个顺序Executor, 并且一次只能执行一个线程. 代码中定义如下:

/**
 * An {@link Executor} that executes tasks one at a time in serial
 * order.  This serialization is global to a particular process.
 */
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

上述SerialExecutor关键代码:

public synchronized void execute(final Runnable r) {
    ...
            try {
                r.run();
            } finally {
                scheduleNext();
            }
    ...
}

 

那么, 多个AsyncTask同时执行变成顺序执行, 是否也是受Executor的约束呢?

我们来看一下AsyncTask.execute(Parmas): 里面简简单单就一行:

return executeOnExecutor(sDefaultExecutor, params);

 

于是明白execute其实也是通过executeOnExecutor()实现的, 只是指定了默认的Executor. 再来看sDefaultExecutor:

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

 这又回到了上面提到的顺序Executor.

 

到这里, 同事碰到问题的原因就找到了:

1. 虽然构造了多个AsyncTask实例, 并且都通过execute()执行起来

2. 但由于它们共享了同一个sDefaultExecutor(它是以static修饰的);

3. sDefaultExecutor同一时间只执行一个线程;

4. 因此这些AsyncTask实例同时启动后是顺序执行的..

 

 ================================ 继续读代码的分割线  ================================

 

在看代码过程中, 注意到几个地方:

1. sDefaultExecutor它是个类静态成员:

    从而整个系统中整个进程中, 所有通过execute()启动的AsyncTask, 都是在顺序执行. 那么如果你的AsyncTask在execute后许久仍不执行, 很可能就是被其他task block住了.

2. sDefaultExecutor它不是final的:

    存在这样的可能性, 重新赋值sDefaultExecutor, 使之可同时执行多个线程. 相应的, 可以找到一个标记为@hide的方法: setDefaultExecutor(Executor exec). 如果通过反射直接操作sDefaultExecutor, 或者调用setDefaultExecutor(), 均可以改变AsyncTask的顺序执行逻辑. 但需要注意到, 这个逻辑改变会影响到系统中所有用到AsyncTask的地方.

3. Android官方文档:

    AsyncTask的文档中有这样的描述: AsyncTasks should ideally be used for short operations (a few seconds at the most.) 如果你的线程需要执行一段较长的时间的话, 还是另谋生路吧(这个生路怎么谋, 文档里也有写, 这里就不列上来了).