我爱编程

19. 线程池

2018-05-27  本文已影响30人  from0

Android 中的线程池就是 java 中的线程池,即 ThreadPoolExecutor 类。

Java 通过 Executors 提供四种线程池:

  1. newCachedThreadPool

    创建一个可缓存的线程池

  2. newFixedThreadPool

    创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

  3. newScheduledThreadPool

    创建一个定长线程池,支持定时及周期性任务执行。

  4. newSingleThreadExecutor

    创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

Executors 是一个线程池的工具类,上面四个方法最终都是调用的 ThreadPoolExecutor。理解 ThreadPoolExecutor 就可以完全理解线程池。

线程池解决了 2 个问题:

  1. 当执行大量异步任务时,通过减少每个任务的调用开销来提高性能。
  2. 提供了限制管理线程资源的方法。

ThreadPoolExecutor

public class ThreadPoolExecutor extends AbstractExecutorService 

构造

    /**
     *
     * @param corePoolSize  保持在线程池中的线程数,即使线程处于空闲状态,除非设置了 allowCoreThreadTimeOut
     * @param maximumPoolSize 线程最大数量
     * @param keepAliveTime 线程数大于 corePoolSize 时,线程池中的空闲线程等待新任务执行的最大时间,超过这个时间,空闲线程就会被终止。
     * @param unit keepAliveTime 的时间单位
     * @param workQueue 任务队列
     * @param threadFactory 线程工厂
     * @param handler 线程被阻塞时的处理者,因为到达了线程的最大数量或者任务队列满了。
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        
        // 检查参数
        if (corePoolSize < 0 ||
                maximumPoolSize <= 0 ||
                maximumPoolSize < corePoolSize ||
                keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        
        // 赋值
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

执行流程

执行流程可以用这张图来概括:


image

通过 execute()方法执行线程池,内部会自动根据我们构造参数的信息分配处理 Runnable。

    public void execute(Runnable command) {
        // Runnable 不可以为空
        if (command == null)
            throw new NullPointerException();
        
        // ctl 是一个 AtomicInteger,用来记录正在运行的线程数量
        int c = ctl.get();
        // 当前核心的线程数量<corePoolSize,就新开一个线程将任务放进去
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        
        // 核心线程正在运行,且任务队列没满
        if (isRunning(c) && workQueue.offer(command)) {
            // 重新检查核心线程
            int recheck = ctl.get();
            // 核心线程没有运行就移除任务,实施拒绝策略
            if (! isRunning(recheck) && remove(command))
                reject(command);
            // 核心线程数量为0,开一个线程
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        // 任务队列
        else if (!addWorker(command, false))
            reject(command);
    }

参考

深入理解Java之线程池

Android 开发艺术探索 11.3

上一篇 下一篇

猜你喜欢

热点阅读