当前位置:编程学习 > JAVA >>

Asynctask解析以及注意事项

[java]  
    说到AsyncTask这个类,好多人其实不太了解。最近看了下代码,把心得分享给大家。 
    AsyncTask的execute的执行流程为 
    先调用ThreadPoolExecutor.execute(mFuture); 
    然后ThreadPoolExecutor.execute(mFuture) 会调用ThreadPoolExecutor.addWorker(mFuture); 
    最后ThreadPoolExecutor.addWorker(mFuture)会调用mFuture的run()方法,run方法中就是该线程要执行操作的地方 
    到此我们来关注一下mFuture,AsyncTask中的mFuture是一个FutureTask,FutureTask实现了Future<V>, Runnable两个接口, 
    Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果,计算完成后只能使用 get 方法来获取结果。 
    mFuture以mWorker作为参数 
    现看mFuture的构造方法: 
public void run() { 
    sync.innerRun(); 
 
    sync是什么呢?Sync类是一个内部类,我们看看它的初始化 
public FutureTask(Callable<V> callable) { 
    if (callable == null) 
        throw new NullPointerException(); 
    sync = new Sync(callable); 
    在看看sync.innerRun()方法: 
void innerRun() { 
    if (!compareAndSetState(READY, RUNNING)) 
        return; 
 
    runner = Thread.currentThread(); 
    if (getState() == RUNNING) { // recheck after setting thread 
        V result; 
        try { 
            result = callable.call(); 
        } catch (Throwable ex) { 
            setException(ex); 
            return; 
        } 
        set(result); 
    } else { 
        releaseShared(0); // cancel 
    } 
    从代码可以看到,其实最终是调用了callable.call()这个方法。 
    从AsyncTask中我们可以知道,我们传入的Callable是我们的WorkerRunnable 
    所以,我们会调用WorkerRunnable的call()方法,在call方法里面 
    返回postResult(doInBackground(mParams)); 
    通知UI线程更新,这就是调用过程 
Notes: 
1: 
    因为AsyncTask里面的内部handler和Executor都是静态变量,所以,他们控制着所有的子类。 
2: 
    我们可以通过AsyncTask.execute()方法来调用系统默认的线程池来处理当前的任务, 
    系统默认的线程池用的是SerialExecutor.这个线程池控制所有任务按顺序执行。也就是一次只执行一条. 
    当前执行完了,才执行下一条.2.3平台以前是所有的任务并发执行,这会导致一种情况,就是其中一条任务执行出问题了,会引起其他任务 
    出现错误. 
3: 
    AsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)你也可以采用这个系统提供的线程池来处理你的任务 
    默认这个线程池是并发处理任务的,也就是不按顺序来.核心为5条,最大128条 
4: 
    你也可以使用自定义的线程池,这样就可以即使的执行你的任务需求,而不是用系统的。因为用系统默认的线程池可以需要等待,它默认 
    是按顺序执行(THREAD_POOL_EXECUTOR)或者最多执行5个(SerialExecutor). 
    自己使用自定义线程池方式如下: 
    new AsyncTask.executeOnExecutor((ExecutorService)Executors.newCachedThreadPool()). 
5:  不要随意使用AsyncTask,除非你必须要与UI线程交互.默认情况下使用Thread即可,要注意需要将线程优先级调低. 
    从google官方文档你也可以看到,AsyncTasks should ideally be used for short operations (a few seconds at the most.) 
    AsyncTask适合处理短时间的操作,长时间的操作,比如下载一个很大的视频,这就需要你使用自己的线程来下载,不管是断点下载还是其它的. 
    当然,如果你需要开启自定义的很多线程来处理你的任务,切记你此时可以考虑自定义线程池 
 */  
public abstract class AsyncTask<Params, Progress, Result> {  
    private static final String LOG_TAG = "AsyncTask";  
    // 核心线程数是要  
    private static final int CORE_POOL_SIZE = 5;  
    // 最大线程数支持128  
    private static final int MAXIMUM_POOL_SIZE = 128;  
    // 这个参数的的意思是当前线程池里面的thread如果超过了规定的核心线程5,如果有线程的空闲时间超过了这个数值,  
    // 数值的单位自己指定,就回收该线程的资源,达到动态调整线程池资源的目的.  
    private static final int KEEP_ALIVE = 1;  
    // ThreadFactory是用来在线程池中构建新线程的方法.可以看到每次构建一个方法,名字都不同.为"AsyncTask # 1++".  
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {  
        private final AtomicInteger mCount = new AtomicInteger(1);  
  
        public Thread newThread(Runnable r) {  
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());  
        }  
    };  
    // 线程池所使用的缓冲队列.FIFO,它用于存放如果当前线程池中核心线程已满,此时来的任务都被放到缓冲队列中等待被处理.  
    // 初始化容量为10  
    private static final BlockingQueue<Runnable> sPoolWorkQueue =  
            new LinkedBlockingQueue<Runnable>(10);  
  
    /** 
     * An {@link Executor} that can be used to execute tasks in parallel. 
     */  
    // 线程池的初始化,指定了核心线程5,最大线程128,超时1s,缓冲队列等, 你在使用asyncTask的时候,可以传入这个参数,  
    // 就可以让多条线程并发的执行了.比如:executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)  
    public static final Executor THREAD_POOL_EXECUTOR  
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,  
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);  
  
    /** 
     * 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();  
    // 消息数值  
    pri
补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,