线程池ThreadPoolExecutor

Posted tonghun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池ThreadPoolExecutor相关的知识,希望对你有一定的参考价值。

 

一 概述

1.线程池产生背景

在多线程环境下,频繁地创建与销毁线程会耗费大量的系统资源,降低运行性能,因此产生了一种设计思想:将创建好的线程放到一个容器中,需要时从容器取得线程,使用完毕将线程归还容器,这样就可以重复利用线程,避免了重复创建与销毁造成的资源消耗,提高了性能。

2.什么是线程池?

元素:线程。
本质:容器。
设计目的:使得线程能够被重复使用,降低系统消耗。
一个以多个线程为元素、通过重复使用降低系统消耗的容器。

二 ThreadPoolExecutor

该类是线程池思想的核心类,继承关系如图。

一个代表性的构造方法;

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

1.coolPoolSize

核心池大小。这个数字是根据一般情况下并发访问的线程数目设定的。默认情况下,线程池创建完毕后,池中并没有线程,有任务到达以后才开始创建线程。

2.maximumPoolSize

线程池中允许出现的最大线程数。维护线程需要消耗系统资源,最大线程数目的设定既考虑高峰时期最大并发访问数量,也兼顾了系统性能。

3.keepAliveTime

这个参数针对的是超出核心池大小的多余线程。设定一个时间,如果多余线程空闲时间超过该值,线程会被终止。默认情况下,只有当线程数目大于核心池大小时才有效,如果allowCoreThreadTimeOut设定为true,当线程数目小于核心池大小时也有效。

4.unit

keepAliveTime的单位。

5.workQueue

一个阻塞队列,用来存储等待执行的任务。BlockingQueue有几个常用的实现类:

  • ArrayBlockingQueue:不常用。
  • LinkedBlockingQueue:常用。
  • SynchronousQueue:常用。

6.threadFactory

线程工厂,用来创建线程。

7.handler

当线程数目到达最大值时,拒绝处理任务时采取的策略。

三 执行过程

1.当线程数目小于核心数目时,每来一个任务就创建一个线程去执行该任务。
2.当线程数目大于等于核心数目时,首先尝试将新到达的任务添加到任务缓存队列中,若添加成功,等待空闲线程执行该任务,添加失败尝试创建新的线程处理该任务。
3.如果线程达到最大数目,新任务达到时会采取拒绝处理策略。

execute()是ThreadPoolExecutor的核心方法,下面对该源码进行分析:

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn\'t, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
       //workerCountOf(c)用于获取线程池中当前线程数目
        if (workerCountOf(c) < corePoolSize) {
            //addWorker(command,true)创建新的线程执行该任务
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //当线程数目大于等于corePoolSize时,首先尝试将任务添加到任务缓存队列中
        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);
    }

addWorker(Runnable firstTask, boolean core)源码:

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
           ........................................................................

            for (;;) {
                int wc = workerCountOf(c);
               //当core=true时,如果线程数目小于corePoolSize,程序继续执行,创建新线程;当core=false时,如果线程数目大于等于
               //maximumPoolSize,程序终止执行,返回false,不会创建新的线程。
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            //为任务创建一个新的线程
            w = new Worker(firstTask);
            ..............................................
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

四 使用

通常不直接使用ThreadPoolExecutor的构造方法来创建对象,而是使用Executors的静态方法来创建对象。

newCachedThreadPool();

corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,使用SynchronousQueue作为任务缓存队列,如果线程池中没有可用的线程,每来一个任务创建一个线程。

newFixedThreadPool(int nThreads);

corePoolSize=nThreads,maximumPoolSize=nThreads,keepAliveTime=0s,使用LinkedBlockingQueue作为任务缓存队列。
线程池执行对象创创建完毕以后,将任务通过execute(Runnable command)方法提交给线程池执行对象即可。

参考:

http://www.cnblogs.com/dolphin0520/p/3932921.html

以上是关于线程池ThreadPoolExecutor的主要内容,如果未能解决你的问题,请参考以下文章

线程池(ThreadPoolExecutor)源码解析

线程池(ThreadPoolExecutor)源码解析

线程池(ThreadPoolExecutor)源码解析

高并发多线程基础之ThreadPoolExecutor源代码分析

如何获取线程池ThreadPoolExecutor正在运行的线程

线程池ThreadPoolExecutor分析