Android - ThreadPoolExecutor线程池源码分析

·  阅读 513

有兴趣的一起看下线程池的原理吧。 源码以API-23为例

ThreadPoolExecutor构造方法

线程池的构造方法有好几个,主要分析这个

  • corePoolSize,核心线程数;
  • maximumPoolSize ,线程池最大线程数,包括核心线程;
  • keepAliveTime,线程timeout时间,线程在这个时间内没有任务需要执行将结束,也就是可以资源回收;
  • unit,timeout的单位,例如毫秒、秒;
  • workQueue,阻塞任务队列,例如LinkedBlockingQueue;
  • handler,抛弃策略,也就是当任务大于最大线程数+阻塞队列长度时,新加入任务的处理方式;
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }
ThreadPoolExecutor.execute 提交任务
   public void execute(Runnable command) {
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {//1
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {//2
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))//3
            reject(command);
    }
  • 注释1:workerCountOf获取当前线程数,当它小于corePoolSize时,将触发addWorker方法添加任务;
  • 注释2:当前线程数大于等于corePoolSize时,则将任务添加到阻塞队列,等待被执行;
  • 注释3:当任务添加阻塞队列失败,那么就执行抛弃策略,也就是构造函数的最后一个参数;
ThreadPoolExecutor.addWorker构建任务

 Worker(Runnable firstTask) {//1
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);//2
 }
 
  private boolean addWorker(Runnable firstTask, boolean core) {
        //省略部分代码
        try {
            w = new Worker(firstTask);//3
            final Thread t = w.thread;
            if (t != null) {
                ......
                if (workerAdded) {
                    t.start();//4
                    workerStarted = true;
                }
            }
        //省略部分代码
        }
        return workerStarted;
    }
    

  • 注释1: Worker的构造函数只有一个,就是添加的任务;
  • 注释2: 创建线程,将Thread与Worker绑定,其实Worker也实现了Runable接口;
  • 注释3: 构建Worker,任务作为参数;
  • 注释4: 启动线程执行任务,为什么启动线程就能执行任务呢?还记得注释2的绑定关系吗?当start启动线程,就是执行Worker.run,而>Worker.run就是执行任务的run;
流程图

1.png

线程如何复用呢
//Worker类中
final void runWorker(Worker w) {
        //省略部分代码
        try {
            while (task != null || (task = getTask()) != null) {//1
                      //省略部分代码
                      task.run();
                      //省略部分代码
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }
  • 注释1,getTask()就是获取堵塞队列中的任务执行,只要队列有任务,Thread就一直执行;
线程如何销毁呢
//Worker类中
  private Runnable getTask() {
         //省略部分代码
      for (;;) {
             //省略部分代码
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;//1
             //省略部分代码
            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) ://2
                    workQueue.take();//3
                if (r != null)
                    return r;//4
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }

    }
  • 注释1:判断线程是否需要设置超时限制,允许核心线程超时当期线程数大于核心线程数,都应该设置超时限制;
  • 注释2,如果需要尝试回收线程,则利用workQueue.poll获取任务;
  • 注释3,如果暂时不考虑回收线程,则利用workQueue.take获取任务;
ThreadPoolExecutor线程池几个重要的角色
BlockingQueue<Runnable> workQueue;//阻塞队列,维护任务;
RejectedExecutionHandler handler;//拒绝处理器
Worker worker;//工作线程,对任务的封装
Runnable command:任务的本身
总结
  • 当前线程数小于核心线程数时,将创建新线程来执行该任务;
  • 当前线程数大于等于核心线程数时,而阻塞队列没有满时,将任务直接加入队列中;
  • 当前线程数大于等于核心线程数时,而且阻塞队列满时,将创建新线程来执行任务;
  • 阻塞队列满,而且线程数大于等于最大线程数时,将会执行抛弃策略。

以上分析有不对的地方,请指出,互相学习,谢谢哦!

分类:
Android
标签:
分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改