Adnroid 面试题 关于AsyncTask源码解析

到底AsyncTask线程池的大小是?

总结:

3.0之前的同时运行的线程数、线程池大小是经验值
3.0之后改为了和CPU数目有关系

  • 5.0 版本 ,同一时刻能运行的线程数是CPU的数目+1,线程总池大小是CPU_COUNT * 2 + 1
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
  • 4.1.2 版本 规定同一时刻能够运行的线程数为5个,线程池总大小为128
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
  • 2.0版本 2.0和4.1.2定义的线程数是一样的,都是5、128
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;

3.0之后对AsyncTask的改进

区别是4.1.2是串行执行多个AsyncTask,而2.0版本是并行执行

注意4.1.2提供了executeOnExecutor方法,可以指定AsyncTask的Executor

public final AsyncTask<Params, Progress, Result> executeOnExecutor (Executor exec, Params... params)

可以利用自定义的Executor把串行改为并行

下面部分内容摘自郭霖的博客 Android AsyncTask完全解析,带你从源码的角度彻底理解

3.0之前是使用Java自带的ThreadPoolExecutor

在3.0版本中AsyncTask的改动还是挺大的,在3.0之前的AsyncTask可以同时有5个任务在执行,而3.0之后的AsyncTask同时只能有1个任务在执行。为什么升级之后可以同时执行的任务数反而变少了呢?这是因为更新后的AsyncTask已变得更加灵活,如果不想使用默认的线程池,还可以自由地进行配置。比如使用如下的代码来启动任务:

Executor exec = new ThreadPoolExecutor(15, 200, 10,  
        TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());  
new DownloadTask().executeOnExecutor(exec);  
//4.1.2中可以使用我们自定义的一个Executor来执行任务,而不是使用SerialExecutor
//上述代码的效果允许在同一时刻有15个任务
//正在执行,并且最多能够存储200个任务。

为什么AsyncTask在UI线程里new实例

InternalHandler 是为了在UI线程中执行更新控件等操作

OnPreExecute、onProgressUpdate、onPostExecute都是在UI线程中执行,内部也都调用了InternalHandler的handleMessage方法

由于静态成员在加载类的时候进行初始化,这就要求AsyncTask的类必须在主线程中加载。

private static final InternalHandler sHandler = new InternalHandler();

private static class InternalHandler extends Handler{
    public void handleMessage(Message msg){
        AsyncTaskResult result = (AsyncTaskResult)msg.obj;
        switch(msg.what){
            case MESSAGE_POST_RESULT:
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

解析 SerialExecutor

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);  
        }  
    }  
}  

解析 ArrayDeque

ArrayDeque是Java6新增的一个类,主要是可以实现队列,也可以实现栈。
想比较LinkedList,ArrayDeque底层是用数组实现循环队列的

源码解析 可以看这儿 ArrayDeque源码图析

找出大于某个数的最小2幂次方

这是ArrayDeque里面的一个方法,ArrayDeque保证长度要是2的幂次方,方便一些按位与、掩码等运算。

private void allocateElements(int numElements) {  
    int initialCapacity = MIN_INITIAL_CAPACITY;  
    // 找到numElements的最小的2的幂整数。  
    // Tests "<=" because arrays aren't kept full.  
    if (numElements >= initialCapacity) {  
        initialCapacity = numElements;  
        initialCapacity |= (initialCapacity >>>  1);  
        initialCapacity |= (initialCapacity >>>  2);  
        initialCapacity |= (initialCapacity >>>  4);  
        initialCapacity |= (initialCapacity >>>  8);  
        initialCapacity |= (initialCapacity >>> 16);  
        initialCapacity++;  //上面得到2的幂次方-1

        if (initialCapacity < 0)   // Too many elements, must back off  
            initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements  
    }  
    elements = (E[]) new Object[initialCapacity];  
}

stackoverflow的回答解释了为什么按位或就能得到2的幂次方-1

Implementation of ArrayDeque.allocateElements (bitwise operations)

    initialCapacity |= (initialCapacity >>>  1);
    initialCapacity |= (initialCapacity >>>  2);
    initialCapacity |= (initialCapacity >>>  4);
    initialCapacity |= (initialCapacity >>>  8);
    initialCapacity |= (initialCapacity >>> 16);

//equals to:

    initialCapacity |= (initialCapacity >>>  1) | (initialCapacity >>>  2) |
                       (initialCapacity >>>  3) | (initialCapacity >>>  4) |
                       (initialCapacity >>>  5) | (initialCapacity >>>  6) |
                       (initialCapacity >>>  7) | (initialCapacity >>>  8) |
                       (initialCapacity >>>  9) | (initialCapacity >>>  10) |
                       (initialCapacity >>>  11) | (initialCapacity >>>  12) |
                       (initialCapacity >>>  13) | (initialCapacity >>>  14) |
                       (initialCapacity >>>  15) | (initialCapacity >>>  16) |
                       (initialCapacity >>>  17) | (initialCapacity >>>  18) |
                       (initialCapacity >>>  19) | (initialCapacity >>>  20) |
                       (initialCapacity >>>  21) | (initialCapacity >>>  22) |
                       (initialCapacity >>>  23) | (initialCapacity >>>  24) |
                       (initialCapacity >>>  25) | (initialCapacity >>>  26) |
                       (initialCapacity >>>  27) | (initialCapacity >>>  28) |
                       (initialCapacity >>>  29) | (initialCapacity >>>  30) |
                       (initialCapacity >>>  31)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值