android线程池分析

一、线程池的优点

1、降低资源消耗,通过重复利用已创建的线程,降低创建和销毁线程造成的系统资源
2、提高响应速度,当任务到达时,不需要等到线程创建了才执行任务
3、提高管理性,可以统一分配、调优和监控

二、线程池ThreadPoolExecutor的使用

三、线程池ThreadPoolExecutor是如何复用的?

我们知道,Thread.start()只能调用一次,一旦这个调用结束,则该线程就到了stop状态,不能再次调用start,则要达到复用的目的,必须不让它进入stop状态,当它处理完一个任务后,接着从任务队列里取出下一个继续处理,直到任务队列没有任务了才结束线程,这就是线程池的原理。下面我们通过源码来分析

ThreadPoolExecutor执行execute()分4种情况
1、若当前运行的线程少于corePoolSize,则创建新线程来执行任务(执行这一步需要获取全局锁)
2、若运行的线程多于或等于corePoolSize,则将任务加入BlockingQueue
3、若无法将任务加入BlockingQueue,则创建新的线程来处理任务(执行这一步需要获取全局锁)
4若创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()

采取上述思路,是为了在执行execute()时,尽可能避免获取全局锁
在ThreadPoolExecutor完成预热之后(当前运行的线程数大于等于corePoolSize),几乎所有的execute()方法调用都是执行步骤2,而步骤2不需要获取全局锁
execute()方法

int c = ctl.get();
// 当前线程数 < 核心线程数coreSize的话,就新建一个Worker,worker里会新建一条线程
if (workerCountOf(c) < corePoolSize) {
    if (addWorker(command, true))
        return;
    c = ctl.get();
}
// 能执行到这里,说明当前线程数 >= coreSize。这样的话,就把任务加入队列workQueue。
if (isRunning(c) && workQueue.offer(command)) {
    int recheck = ctl.get();
    if (! isRunning(recheck) && remove(command))
        reject(command);
    else if (workerCountOf(recheck) == 0)
        addWorker(null, false);
}
else if (!addWorker(command, false))
    reject(command);

线程池开始执行第一个Runnable任务时,当前线程数肯定是少于核心线程数据,所以会执行addWorker(command,true)。它的关键代码如下:

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;

它会创建一个Worker,然后添加到workers里,然后执行t.start(),这个t就是worker里新建的线程,Worker的关键代码如下:

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker. */
        public void run() {
            runWorker(this);
        }
}

构造函数里持有了我们传进来的runnable,以及创建了一条新的线程,worker本身也实现了Runnable接口,它对firstTask装饰了一层,当调用worker里的线程start()的时候会调用runWorkr(this)方法

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

重点就是这个循环了,它是实现线程复用的关键,首先进入循环task是不会空的所以执行循环体,然后获取锁,接着我们看到task.run(),这行就是执行我们传进来的Runnable的run()方法,task.run的前后有两行代码beforeExecute(wt, task);和afterExecute(task, thrown);,它们分别代码任务执行前后,有需要的话我们可以复写这两个方法来监听这两个状态,解锁置空task,这时接着跑下一个循环,这时候task==null,所以跑task=getTask()!=null了,到这里我们就可以推测getTask()的作用就是从BlockingQueue任务队列中尝试获取一个任务,如果能取到就接着跑循环体,如果取不到的话,会阻塞线程,知道有任务或超时,这样一条线程执行了多个任务就达到了复用的目的了。能达到线程复用的一个关键就是BlockingQueue ,workQueue是BlockingQueue的实例字面上理解就是阻塞队列,当workQueue.take()或workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS),如果试图的这两操作无法立即执行,该方法调用的线程将会发生阻塞,直到能够执行或超时,poll(keepAliveTime,TimeUnit.NANOSECONDS)中的keepAliveTime就是线程的存活时长,在这时长里阻塞队列都得不到执行,那么这条线程将会被stop掉,正是这个阻塞,才给任务线程有等待下一个任务到来的机会,从而避免收到工作任务的时候再次新建线程,复用了线程。

四、线程池的BlockingQueue

(https://www.jianshu.com/p/273051b9fae2)
(https://blog.csdn.net/qq_26881739/article/details/80983495)

你可能感兴趣的:(android线程池分析)