AsyncTask与线程池

来源:互联网 发布:圣安德鲁斯大学cs知乎 编辑:程序博客网 时间:2024/05/22 05:31

线程池的创建

  • 为什么使用线程池
    1. 线程的创建和销毁由线程池维护,一个线程在完成任务后并不会立即销毁,而是由后续的任务复用这个线程,从而减少线程的创建和销毁,节约系统的开销
    2. 线程池旨在线程的复用,这就可以节约我们用以往的方式创建线程和销毁所消耗的时间,减少线程频繁调度的开销,从而节约系统资源,提高系统吞吐量
    3. 在执行大量异步任务时提高了性能
    4. Java内置的一套ExecutorService线程池相关的api,可以更方便的控制线程的最大并发数、线程的定时任务、单线程的顺序执行等

创建线程池方法

  1. newFixedThreadPool(int number): 创建包含固定个数的线程池

    public static ExecutorService getFixedThreadPool(){    //创建三个线程队列的方法.只能有三个线程存在,如果超过就加入队列等待执行    return Executors.newFixedThreadPool(3);}
  2. newCachedThreadPool() :根据实际情况调整线程的数量的线程池

    • 如果线程池中的所有线程都正在工作,而此时有新任务提交,那么将会创建新的线程去处理该任务
    • 如果此时线程池中有执行完毕的线程再来任务就复用该线程执行
    • 通过配置线程的“保持活动时间”的参数,若线程池中的空闲线程的空闲时间超过该“保存活动时间”则立刻停止该线程,而该线程池默认的“保持活动时间”为60s。不会导致线程无限增加
      /** * 创建一个根据实际需求变化的线程池 * @return */public static ExecutorService getNewCachedThreadPool(){    return Executors.newCachedThreadPool();}
  3. newSingleThreadExecutor() :

    • 该方法返回一个只有一个线程的线程池,即每次只能执行一个线程任务,多余的任务会保存到一个任务队列中,等待这一个线程空闲,当这个线程空闲了再按FIFO方式顺序执行任务队列中的任务。
      public static ExecutorService getNewSingleThreadPool(){    //创建只有一个线程的线程池    return Executors.newSingleThreadExecutor();}
  4. newScheduledThreadPool() :

    • 该方法返回一个可以控制线程池内线程定时或周期性执行某任务的线程池
          ScheduledExecutorService newScheduleThreadPool = ExcutorFractory.getNewScheduleThreadPool();    //正常的调用,跟上面的一样//        newScheduleThreadPool.execute(new Runnable(){});    //延迟2秒后执行该任务    newScheduleThreadPool.schedule(new Runnable() {        @Override        public void run() {            String name = Thread.currentThread().getName();            Log.e("cai" , "当前线程:" + name + "执行的是第:"  +"个任务");        }    }, 2, TimeUnit.SECONDS);    //延迟1秒后,每隔2秒执行一次该任务    newScheduleThreadPool.scheduleAtFixedRate(new Runnable() {        @Override        public void run() {            String name = Thread.currentThread().getName();            Log.e("cai" , "当前线程:" + name + "执行的是第:"  +"个任务");        }    }, 1, 2, TimeUnit.SECONDS);
  5. newSingleThreadScheduledExecutor() :调取同上
    创建一个可以定时或者周期性执行任务的线程池,该线程池的线程数为1 ;

  6. 以上方法的内部实现都是通过创建一个ThreadPoolExecutor对象来创建的:

    • 注意参数:workQueue, 任务队列,主要用来存储已经提交但未被执行的任务,不同的线程池采用的排队策略不一样
      • workQueue: BlockingQueue对象,而泛型则限定它是用来存放Runnable对象的
        1. newFixedThreadPool()—>LinkedBlockingQueue :无界的队列
          • LinkedBlockingQueue是一个链表实现的阻塞队列,在链表一头加入元素,如果队列满,就会阻塞,另一头取出元素,如果队列为空,就会阻塞。
        2. newSingleThreadExecutor()—>LinkedBlockingQueue :无界的队列
        3. newCachedThreadPool()—>SynchronousQueue :直接提交的队列
          • SynchronousQueue内部并没有数据缓存空间
        4. newScheduledThreadPool()—>DelayedWorkQueue :等待队列
        5. newSingleThreadScheduledExecutor()—>DelayedWorkQueue:等待队列
        6. ArrayBlockingQueue(有界的队列)
        7. PriorityBlockingQueue(优先级队列)

自定义线程池ThreadPoolExecutor

  1. 按任务的优先级来处理的线程池
      /**     * 返回一个自定义的优先级线程池     * @return     */    public static ExecutorService getPriorityThreadPool(){        return new ThreadPoolExecutor(3,3,0L, TimeUnit.SECONDS,        new PriorityBlockingQueue<Runnable>()) ;    }/** * 创建一个实现Runnable接口的类,并向外提供一个抽象方法供我们实现自定义功能, * 并实现Comparable接口,实现这个接口主要就是进行优先级的比较 * Created by shiqiang on 2017/5/31. */public abstract class PriorityRunnable implements Runnable , Comparable<PriorityRunnable>{    private int priority;    public PriorityRunnable(int priority) {        if (priority < 0 ){            throw new IllegalArgumentException();        }        this.priority = priority;    }    @Override    public void run() {        doThing();    }    protected abstract void doThing() ;    @Override    public int compareTo(@NonNull PriorityRunnable another) {        int my = this.priority;        int other = another.getPriority();        return my < other ? 1 : my > other ? -1 : 0;    }    public int getPriority() {        return priority;    }}//调用的方法        ExecutorService priorityThreadPool = ExcutorFractory.getPriorityThreadPool();        for (int i = 0; i < 10; i++) {            final int priory = i ;            priorityThreadPool.execute(new PriorityRunnable(priory) {                @Override                protected void doThing() {                    String name = Thread.currentThread().getName();//                    Log.e("cai" , "当前线程:" + name + "执行的是第:" + priory +"个任务");                    try {                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            });        }

扩展自己的线程

  • ThreadPoolExecutor也向外提供了三个接口供我们自己扩展满足我们需求的线程池,这三个接口分别是:ThreadPoolExecutor内部的runWorker()方法中调用
    1. beforeExecute() - 任务执行前执行的方法
    2. afterExecute() -任务执行结束后执行的方法
    3. terminated() -线程池关闭后执行的方法
    这三个方法在ThreadPoolExecutor内部都没有实现
public class MyThreadPoolExecutor extends ThreadPoolExecutor {    private ReentrantLock pauseLock = new ReentrantLock();    private Condition unpaused = pauseLock.newCondition();    public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);    }    @Override    protected void beforeExecute(Thread t, Runnable r) {        super.beforeExecute(t, r);        Log.e("cai", "线程:" + t.getName() + "准备执行任务!");    }    @Override    protected void afterExecute(Runnable r, Throwable t) {        super.afterExecute(r, t);        Log.e("cai", "线程:" + Thread.currentThread().getName() + "任务执行结束!!");    }    @Override    protected void terminated() {        super.terminated();        Log.e("cai",  "线程结束!!");    }}

特殊的线程池AsyncTask() ;

  • AsyncTask和Handler对比

    1. AsyncTask实现的原理,和适用的优缺点

      • AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.
      • 使用的优点: 简单,快捷 ; 过程可控
      • 使用的缺点:
        1. 在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.
        2. Handler异步实现的原理和适用的优缺点
    2. 在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)àthread(子线程)运行并生成Message-àLooper获取Message并传递给HandleràHandler逐个获取Looper中的Message,并进行UI变更。

      • 使用的优点:

        1. 结构清晰,功能定义明确
        2. 对于多个后台任务时,简单,清晰
      • 使用的缺点:

        1. 在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)
    3. AsyncTask介绍
      Android的AsyncTask比Handler更轻量级一些,适用于简单的异步处理。
      首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避免的。

      1. AsyncTask内部维持一个静态的Handler,初始化的时候必须在UI主线程中;
      2. AsyncTask调取excute()实际是调取executeOnExecutor()指定调取的线程池版本不同默认调取也不同现在是FatureTask中SerialExecutor(串行),以前用过并行

        @MainThreadpublic final AsyncTask<Params, Progress, Result> execute(Params... params) {return executeOnExecutor(sDefaultExecutor, params);}@MainThreadpublic final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,    Params... params) {mStatus = Status.RUNNING;onPreExecute();mWorker.mParams = params;//exec是就是我们传进来的sDefaultExecutor。那么接下来我们看看sDefaultExecutor究竟是什么。在AsyncTask类的源码中 exec.execute(mFuture);return this;}
      3. exec是就是我们传进来的sDefaultExecutor。那么接下来我们看看sDefaultExecutor究竟是什么。在AsyncTask类的源码中

        //新建的serialExecute()线程池 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
      4. serialExecute()线程池;

        /**参数r就是我们传入的mFuture的run方法,而mFuture的run方法内部会调用mWorker的call方法,然后就会调用doInBackground方法,我们的后台任务也就开始执行了*/public synchronized void execute(final Runnable r) {mTasks.offer(new Runnable() {    public void run() {        try {            //传递进来的Runable            r.run();        } finally {            scheduleNext();        }    }});if (mActive == null) {    scheduleNext();}}
    4. r.run() -> mWorker.call()中调取doInBackgroud():@WorkerThread后台工作进程

       mWorker = new WorkerRunnable<Params, Result>() {        public Result call() throws Exception {            mTaskInvoked.set(true);            Result result = null;            try {                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                result = doInBackground(mParams);                Binder.flushPendingCommands();            } catch (Throwable tr) {                mCancelled.set(true);                throw tr;            } finally {                //如果doInbackgroud执行完毕或者暂停进程调取PostResult方法                postResult(result);            }            return result;        }    };
    5. 注意在doInBackgroud中调取publishProgress()更新数据:注意其运行在工作线程,子线程中,发送Handler给UI线程的Handler;

       @WorkerThreadprotected final void publishProgress(Progress... values) {    if (!isCancelled()) {        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,                new AsyncTaskResult<Progress>(this, values)).sendToTarget();    }}
    6. 同理4.中finally()时调取postResult(),同样是使用Handler发送一个消息给UI线程

       private Result postResult(Result result) {    @SuppressWarnings("unchecked")    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,            new AsyncTaskResult<Result>(this, result));    message.sendToTarget();    return result;}
    7. AsyncTask中静态Handler();

       private static class InternalHandler extends Handler {    public InternalHandler() {        super(Looper.getMainLooper());    }    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})    @Override    public void handleMessage(Message msg) {        AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;        switch (msg.what) {            case MESSAGE_POST_RESULT:                // 使用postResult()发送的结果数据                result.mTask.finish(result.mData[0]);                break;            case MESSAGE_POST_PROGRESS:                //publishProgress()通知更新控件进度的                result.mTask.onProgressUpdate(result.mData);                break;        }    }}
    8. onProgressUpdate()更新控件在MainThread:UI线程

      @MainThreadprotected void onProgressUpdate(Progress... values) {}
    9. finish()方法:

      private void finish(Result result) {//如果在4.中的doInbackGroud中取消时候调取postResult后调取AsyncTask中的Oncancelled(),否则下载完成以后调取onPostExecute(); if (isCancelled()) {    onCancelled(result);} else {    onPostExecute(result);}  //把mStatus设为FINISHED,表示当前AsyncTask对象已经执行完毕;mStatus = Status.FINISHED;}