ThreadPoolExecutor详解

推荐阅读资料点击这里

第一部分:

该类有以下几个构造函数:
1、public ThreadPoolExecutor(int corePoolSize,//核心线程数量
                                                  int maximumPoolSize,
                                                  long keepAliveTime,
                                                  TimeUnit unit,
                                                  BlockingQueue<Runnable> workQueue) {
           

             this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

 

corePoolSize

核心线程数量,线程池刚创建的时候,线程数量为0,当每次执行execute添加新任务会在线程池中创建一个线程,直到线程数量达到corePoolSize。

maximumPoolSize

最大线程数量,当线程数量达到corePoolSize时,执行execute后会将任务添加到workQueue中,等待执行

keepAliveTime

当线程数量大于corePoolSize时,线程空闲时间超过keepAliveTime会被销毁,直到线程数量回落到corePoolSize。

unit

与keepAliveTime搭配使用,是一个时间单位,有天、小时、秒等。

workQueue

在线程数量达到corePoolSize时,后面再提交的任务存放到workQueue中进行排队,等待执行。

 

上面这个构造函数最终会调用另外一个构造函数

2、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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

前面的5个参数和第一个参数类似,现在来分析另外两个参数

threadFactory

这是一个线程工厂,用来生产线程对象,对于默认线程工厂(可以实现自己的线程工厂)来说创建对象的时候传入实现了Runnable接口的对象。下面是默认的线程工厂类:

static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();//这个是系统安全管理器(有空可以去了解一下)
            group = (s != null) ? s.getThreadGroup() :Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +poolNumber.getAndIncrement() + "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(),0);
            if (t.isDaemon())
                t.setDaemon(false);//启动一个用户线程(不是守护线程)
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);//普通线程优先级
                return t;
        }
    }

这个类是用来生产线程的,通过newThread函数来创建线程,里面通过传入实现Runnable接口类对象(这个对象在提交任务的时候会进行传入)。

handler

这个对象用来拒绝执行新添加的任务,抛出异常。实现接口RejectedExecutionHandler的类定义如下:

/**
     * A handler for rejected tasks that throws a
     * {@code RejectedExecutionException}.
     */
    public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

通过函数rejectedExecution抛出异常。那么什么情况下会抛出异常,后面会讲到。

 

3、public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }

这个构造函数可以用来设置自己的线程工厂,handler采用的是默认的。

给一个例子:

ThreadPoolExecutor scheduler = new ThreadPoolExecutor(1,3,60*60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(200),new ThreadFactory(){

      @Override

      public Thread newThread(Runnable r){

            Thread t;

             t  = new Thead(r,"AsyncRequestPersistence");

             return t;

);

上面在构造一个类对象scheduler时采用了自己的线程工厂。

 

4、public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

这个构造函数可以让用户设置自己实现RejectedExecutionHandler接口的类对象,也就是说一旦线程数量达到了最大,此时外界还在提交任务时应该如何处理这个问题。这个过程交由用户自己进行处理。

 

以上就是ThreadPoolExecutor类的四个构造函数。关于线程池对象关系图如下所示:

08d1d312ed1

第二部分

我们开始分析任务提交函数,总共有两个提交任务的函数,一个是submit,另外一个是execute。execute是从Executor接口继承过来,而submit是从ExecutorService接口继承过来,submit函数最终都会调用execute函数。

submit

我们先来看看相关类接口之间的关系图:

clip_image002

可以看到FutureTask类既可以有Runnable的run功能,又有Future接口的取消、获得线程执行结果值等功能。

submit总共有三个函数

1、public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

2、public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

3、public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

我们看到不管传递的参数是Runnable实现类还是Callable实现类,返回值类型都是Future。第一个和第二个函数还好理解,唯一的区别就是参数的个数不同,那么我们来看一下第3个函数,它是如何将Callable实现类转换成Future的。首先看一下newTaskFor函数

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}

FutureTask类有两个构造函数:

1、public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable

}

2、public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
 }

第一个构造函数会将Callable实现类对象赋值到类成员变量callable,而第二个构造函数会将Runnables实现类对象转换成Callable实现类对象,我们来看看它是怎么转换的。

public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
}
返回的是继承了RunnableAdapter类对象,这个类的定义如下:

static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }

可以看到这个类实现了接口Callable,将Runnable实现类对象赋值到task成员变量中,result同样处理了,同事实现的call()函数中执行了run函数,同时返回result值。

综上来看,不管是Callable,还是Runnable,都是汇聚成了一个Callable实现类,前者的call函数调用的是Callable实现类对象的call函数,后者call函数调用的是Runnable实现类中的run函数,同时还有返回值result。

现在进入到execute函数中

在开始分析这个函数前,我们先来了解一下线程池相关变量

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS;//111 可以新加线程,同时可以处理queue中的线程
private static final int SHUTDOWN   =  0 << COUNT_BITS;//000 不增加新线程,但是处理queue中的线程
private static final int STOP       =  1 << COUNT_BITS;//001 不增加新线程,同时不处理queue中的线程
private static final int TIDYING    =  2 << COUNT_BITS;//010 所有的线程都终止了(queue中),同时workerCount为0,那么此时进入TIDYING
private static final int TERMINATED =  3 << COUNT_BITS;//011 方法结束,变为TERMINATED

// Packing and unpacking ctl
private static int runStateOf(int c)     { return c & ~CAPACITY; }
private static int workerCountOf(int c)  { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }

从第二行开始分析,COUNT_BITS的值为29,关于在计算机中,数字经过原码->反码->补码过程得到最终的值,计算机中存储的值是经过这些转换得来的,正数的原码、反码、补码都相同,负数则不同,例如 int 型的1的原码、反码、补码为

00000000 00000000 00000000 00000001

int型-1的原码、反码、补码为:

10000000 00000000 00000000 00000001 原码

11111111 11111111 11111111 11111110 反码

11111111 11111111 11111111 11111111 补码

根据上面的描述,CAPACITY 为1向左移动29位,变成:

00100000 00000000 00000000 00000000

前三位为001,后面29位为0,值为2^29,然后再在这个基础上减去1变成2^29-1,原码、反码、补码变成:

00011111 11111111 11111111 11111111

RUNNING为:

11100000 00000000 00000000 00000000

SHUTDOWN为:

00000000 00000000 00000000 00000000

STOP为:

00100000 00000000 00000000 00000000

TIDYING为:

01000000 00000000 00000000 00000000

TERMINATED为:

01100000 00000000 00000000 00000000

runStateOf函数中c & ~CAPACITY;就是c和11100000 00000000 00000000 00000000进行"与"操作

workerCountOf函数中c & CAPACITY;就是c和00011111 11111111 11111111 11111111进行"与"操作

ctlOf函数就是rs和wc进行"或"操作

经过上面的分析,可以得出,高三位用来记录线程池的各种状态,而其他的29位用来统计线程池中的线程数量。

好了,我们继续下面的execute函数分析:

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();

        //如果当前运行的线程数量小于核心线程数量
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))//新建一个worker
                return;
            c = ctl.get();
        }

        //如果有线程在运行,同时任务被成功提交到队列中
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))//如果不能新加线程,同时不可以处理queue中的线程,那么就移除掉command
                reject(command);
            else if (workerCountOf(recheck) == 0)//上下两个操作都有addWorker的操作,但是如果在workQueue.offer的时候Worker变为0,
                                                                         //那么将没有Worker执行新的task,所以增加一个Worker.
                addWorker(null, false);
        }

        //如果workQueue满了,那么这时候可能还没到线程池的maxnum,所以尝试增加一个worker
        else if (!addWorker(command, false))
            reject(command);//如果worker数量达到上限,那么就拒绝此线程
    }

在讲addWorker前,我们先分析一下retry的使用方法。

        //retry:// 1(行2)
        for (int i = 0; i < 10; i++) {
            retry:// 2(行4)
            while (i == 5) {
                break retry;

     //continue retry;
            }
            System.out.print(i + " ");
        }

retry相当于一个标记,只用在循环里面,很像goto语句,break到retry字符处。如果retry没有在循环(for,while)里面,在执行到retry时,就会跳出整个循环。如果retry在循环里面,可以理解为跳到了关键字处执行,不管几层循环。continue理解也是一样。所以下面的执行结果有以下情况:

在采用行2的retry情况下:

        采用break retry:

        0 1 2 3 4 

        采用continue retry:

        0 1 2 3 4 6 7 8 9

在采用行4的retry情况下:

         采用break retry:

          0 1 2 3 4 5 6 7 8 9

          采用continue retry:

           0 1 2 3 4然后一直在while中循环

 

现在进入到addWorker中

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

           /*从这里是可以看出一些策略的
          首先,在rs>SHUTDOWN时,拒绝一切线程的增加,因为STOP是会终止所有的线程,同时移除Queue中所有的待执行的线程的,所以也不需要增加first=null的Worker了
其次,在SHUTDOWN状态时,是不能增加first!=null的Worker的,同时即使first=null,但是此时Queue为Empty也是不允许增加Worker的,SHUTDOWN下增加的Worker主要用于消耗Queue中的任务。
SHUTDOWN状态时,是不允许向workQueue中增加线程的,isRunning(c) && workQueue.offer(command) 每次在offer之前都要做状态检测,也就是线程池状态变为>=SHUTDOWN时不允许新线程进入线程池了。*/

            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);

                //如果当前线程池中的线程数量大于等于最大容量那么返回false

                //wc >= (core ? corePoolSize : maximumPoolSize))这个就要看core的值
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;

                //采用cas方式添加线程数量,如果添加成功了那么中断retry处的for循环
                if (compareAndIncrementWorkerCount(c))
                    break retry;

                //如果添加线程数量失败了

                //再次获取当前线程池信息
                c = ctl.get();  // Re-read ctl

                //如果当前线程池状态改变了,那么重新执行retry处的for循环
                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 {

            //创建Worker实例
            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;
    }

 

猜你喜欢

转载自blog.csdn.net/weixin_39935887/article/details/81081576
今日推荐