JAVA线程池源码深度解析

目录

JAVA线程池

ExecutorService

AbstractExecutorService

ThreadPoolExecutor

总结


今天我们来说一说java编程中一个非常重要的工具:java线程池,顾名思义,线程池就是存放线程的池子。要使用线程的时候从池子里面拿出来,不用了再放回去。接下来我们将从源码的角度一步步分析java线程池的奥义。

JAVA线程池

先来看一下java线程池(ThreadPoolExecutor)大致的一个类图

可以看到ThreadPoolExecutor的父接口有ExecutorExecutorService,其中ExecutorService是对Executor接口的扩展,AbstractExecutorServiceThreadPoolExecutor父类,这个类中也实现一些非常重要的方法。需要重点分析的还是ThreadPoolExecutorService,我们通常会使用如下代码来创建java线程池

    public void commit() throws InterruptedException {
     
        ExecutorService executor = new ThreadPoolExecutor(10, 20, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(50));
        executor.execute(new Runnable() {
            @Override
            public void run() {
                // do something...
            }
        });
    }

我们来看一下顶层接口Executor

public interface Executor {

    void execute(Runnable command);
}

里面只有一个方法execute,是java线程池最核心的方法。返回类型是void,这个方法入参是一个runnable的实例,代表提交一个任务。

ExecutorService

ExecutorService是对Executor接口的扩展,这个接口中提供了更加丰富的功能。我们常用的也是这个接口。

public interface ExecutorService extends Executor {

    /**
     * 关闭线程池,不接受新的任务。但是这个方法并不会终止正在执行的任务
     */
    void shutdown();

    /**
     * 也是关闭线程池,不接受新的任务。但是这个方法会停止所有正在执行的任务
     */
    List<Runnable> shutdownNow();

    /**
     * 判断线程池是否已经被关闭
     */
    boolean isShutdown();

    /**
     * 调用shutDown或者shutDownNow后,如果所有任务都完成了,返回true,否则返回false
     */
    boolean isTerminated();

    /**
     * 调用这个方法会等待所有任务完成,并且指定了等待的超时时间,返回是否等待超时。
     * 不论是调用shutDown还是shutDownNow,都不会等待任务结束。
     * 所以我们应该是先调用shutDown/shutDownNow,再调用此方法等待所有任务完成
     */
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

    /**
     * 提交一个任务,不同于execute方法,这里的入参是callable,并且返回值是Future
     */
    <T> Future<T> submit(Callable<T> task);

    /**
     * 提交一个任务,但是这里的任务是runnable,
     * runnable执行run后是无返回值的,所以这里传入的result直接作为返回值。
     */
    <T> Future<T> submit(Runnable task, T result);

    /**
     * 提交一个runnable任务
     */
    Future<?> submit(Runnable task);

    /**
     * 执行传入的所有的任务
     */
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

    /**
     * 执行的传入的所有任务,并指定超时时间
     */
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    /**
     * 执行传入的所有任务,只要其中一个任务完成这个方法就可以返回了,返回这个任务的执行结果
     */
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

    /**
     *同上一个方法,只不过这个方法指定了超时时间
     */
    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

从这里我们看到,线程池提交任务的方法有execute和submit,submit和execute最大区别在于submit方法可以获取到线程的执行结果。这里涉及到一个很重要的类:FutureTask,我们下面来简单看下FutureTask的类图

我们看到FutureTask实现了RunnableFuture,而RunnableFuture继承了Runnable和Future,再来看看FutureTask类中的重要属性和构造方法

public class FutureTask<V> implements RunnableFuture<V> {
    /**
     * 当前任务的执行状态,有以下七种,初始状态为NEW
     */
    private volatile int state;
    private static final int NEW          = 0;
    private static final int COMPLETING   = 1;
    private static final int NORMAL       = 2;
    private static final int EXCEPTIONAL  = 3;
    private static final int CANCELLED    = 4;
    private static final int INTERRUPTING = 5;
    private static final int INTERRUPTED  = 6;

    /** 这个属性很重要,就是依靠它来执行任务的 */
    private Callable<V> callable;
    /** 调用get时,返回的result*/
    private Object outcome; // non-volatile, protected by state reads/writes
    /** 真正执行callable任务的线程 */
    private volatile Thread runner;

    ......

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

    public FutureTask(Runnable runnable, V result) {
        // 这里会把runnable 和 result组装成一个callable对象
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
    ......
}

submit方法之所以可以获取线程执行结果,全依赖于callable和FutureTask。FutureTask实现了Runnablerun方法,在run方法中会调用callable.call()获取执行结果,并将执行结果就存储在FutureTask中。

调用submit方法的时候,直接将callable/runnable对象包装成FutureTask,然后调用FutureTask.run()。最终返回FutureTask对象。我们调用FutureTask.get()就可以阻塞获取到线程的执行结果了。

本文不对FutureTask做详细讲解,我们接着看AbstractExecutorService

AbstractExecutorService

AbstractExecutorService类实现了许多父类的方法,供子类使用

public abstract class AbstractExecutorService implements ExecutorService {

    /**
     * 将runnable和value包装成FutureTask,以便获取线程执行结果
     */
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }

    /**
     * 将callable包装成FutureTask,以便获取线程执行结果
     */
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }

    /**
     * 提交任务,返回Future
     */
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        // 组装FutureTask
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        // 将任务交给子类的execute方法去执行
        execute(ftask);
        return ftask;
    }

    /**
     * 提交任务,返回Future,入参跟上面的不一样
     */
    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        // 组装FutureTask
        RunnableFuture<T> ftask = newTaskFor(task, result);
        // 将任务交给子类的execute方法去执行
        execute(ftask);
        return ftask;
    }

    /**
     * 提交任务
     */
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

    /**
     * 将collection中的任务提交给线程池执行,只要有一个任务完成,这个方法就可以返回了
     */
    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
                              boolean timed, long nanos)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (tasks == null)
            throw new NullPointerException();
        // 获取集合中任务的数量
        int ntasks = tasks.size();
        if (ntasks == 0)
            // 没有任务抛出异常
            throw new IllegalArgumentException();
        // 用Future来包装任务
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
        // ExecutorCompletionService这个类的构造方法传入了this作为真正的Executor
        // 这个方法会在每个任务完成后,把被FutureTask包装好的callable任务保存到一个LinkedBlokingQueue中
        ExecutorCompletionService<T> ecs =
            new ExecutorCompletionService<T>(this);

        try {
            // 这里可以学习一下人家的异常处理
            ExecutionException ee = null;
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
            // 迭代所有的callable任务
            Iterator<? extends Callable<T>> it = tasks.iterator();

            // 这里调用了ecs.submit提交一个任务给线程池,并且将封装每个任务的FutureTask保存在futures中
            futures.add(ecs.submit(it.next()));
            // 任务数-1
            --ntasks;
            // 从名字都可以看出来,这个代表正在执行的任务数
            int active = 1;

            for (;;) {// 注意:这里是个循环
                // 我们上面说ExecutorCompletionService中有个LinkedBlockingQueue用于保存每个任务的FutureTask。
                // 那么这里调用poll方法尝试将FutureTask取出来,这里的poll方法是非阻塞的
                Future<T> f = ecs.poll();
                // 如果f为null,说明前面提交的任务还没执行完成。
                if (f == null) {
                    // 我们说这个方法只要有一个任务执行完成就返回了,
                    // 现在还没有任务执行完成,那么接着执行后面的任务
                    if (ntasks > 0) {
                        --ntasks;
                        futures.add(ecs.submit(it.next()));
                        ++active;
                    }
                    // 如果这里的active为0,说明所有的任务都执行失败了,从这里break出去
                    else if (active == 0)
                        break;
                    // 进入这个分支说明已经没有任务了并且需要检测超时
                    else if (timed) {
                        // 再poll一次,等待nanos这么久,看有没有任务完成
                        f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
                        // 如果超时,抛出异常跳出循环
                        if (f == null)
                            throw new TimeoutException();
                        nanos = deadline - System.nanoTime();
                    }
                    // 到这一步说明已经没有任务了,也没有设置超时,
                    // 那么调用take方法阻塞,直到有任务执行完成
                    else
                        f = ecs.take();
                }
                // 如果f!=null说明有任务执行完成了
                if (f != null) {
                    // 正在执行的任务数-1
                    --active;
                    try {
                        // 调用FutureTask.get()阻塞等待执行结果并返回结果
                        return f.get();
                    } catch (ExecutionException eex) {
                        ee = eex;
                    } catch (RuntimeException rex) {
                        ee = new ExecutionException(rex);
                    }
                }
            }

            if (ee == null)
                ee = new ExecutionException();
            throw ee;

        } finally {
            // 最后在return之前,取消其他还没结束的任务
            for (int i = 0, size = futures.size(); i < size; i++)
                futures.get(i).cancel(true);
        }
    }
    // 这个方法就是调用上面的doInvokeAny,不带超时
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException {
        try {
            return doInvokeAny(tasks, false, 0);
        } catch (TimeoutException cannotHappen) {
            assert false;
            return null;
        }
    }
    // 调用上面的doInvokeAny,带超时
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                           long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        return doInvokeAny(tasks, true, unit.toNanos(timeout));
    }
    // 这个方法就是提交collection中所有的callable任务,并返回结果列表
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException {
        if (tasks == null)
            throw new NullPointerException();
        // 使用Future包装任务
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        // 任务是否完成的标志位
        boolean done = false;
        try {
            for (Callable<T> t : tasks) {
                // 将所有的callable任务包装成FutureTask
                RunnableFuture<T> f = newTaskFor(t);
                // 将所有的FutureTask保存到futures这个List中
                futures.add(f);
                // 提交任务
                execute(f);
            }
            // 循环遍历所有的FutureTask
            for (int i = 0, size = futures.size(); i < size; i++) {
                Future<T> f = futures.get(i);
                // 如果这个任务还没完成
                if (!f.isDone()) {
                    try {
                        // 调用FutureTask.get()阻塞,直到任务完成获取到值
                        f.get();
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    }
                }
            }
            // 代表所有任务都已执行完成
            done = true;
            // 返回FutureTask的List列表
            return futures;
        } finally {
            // 如果!done,说明有任务没完成,就是说try中代码出现了异常,取消任务
            if (!done)
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);
        }
    }
    // 跟上面的invokeAll不同的地方,在于这个方法支持超时机制
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                         long timeout, TimeUnit unit)
        throws InterruptedException {
        if (tasks == null)
            throw new NullPointerException();
        long nanos = unit.toNanos(timeout);
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        boolean done = false;
        try {
            for (Callable<T> t : tasks)
                futures.add(newTaskFor(t));

            final long deadline = System.nanoTime() + nanos;
            final int size = futures.size();

            for (int i = 0; i < size; i++) {
                // 调用execute提交任务
                execute((Runnable)futures.get(i));
                // 这里得到的nanos代表剩余的时间
                nanos = deadline - System.nanoTime();
                // 每个线程提交后判断一下超时
                if (nanos <= 0L)
                    return futures;
            }
            // 循环所有的FutureTask
            for (int i = 0; i < size; i++) {
                Future<T> f = futures.get(i);
                // 如果这个任务还没有完成
                if (!f.isDone()) {
                    // 先判断一下是否超时
                    if (nanos <= 0L)
                        return futures;
                    try {
                        // 到这里调用带超时的FutureTask.get方法
                        // 阻塞获取每个任务的执行结果,直到任务完成
                        f.get(nanos, TimeUnit.NANOSECONDS);
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    } catch (TimeoutException toe) {
                        return futures;
                    }
                    nanos = deadline - System.nanoTime();
                }
            }
            done = true;
            return futures;
        } finally {
            // 超时或者try中出现异常都会进入到这个分支,取消任务
            if (!done)
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);
        }
    }

}

到这里,我们已经对AbstractExecutorService有了一个大致的了解。

下面我们接着看JAVA线程池最核心的类:ThreadPoolExecutor,这个类的execute()方法才是最终开启线程执行任务的地方

ThreadPoolExecutor

ThreadPoolExecutor这个类中实现了一系列java线程池管理最核心的方法。老规矩我们先来看看它的构造方法

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

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

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), 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;
    }

Java线程池有如下几个核心参数:

  • corePoolSize:核心线程数
  • maximumPoolSize:线程池最大线程数
  • keepAliveTime:空闲线程存活的时间,如果线程空闲了keepAliveTime这么久以后,还是没有任务分配给它,那么线程会被关闭。当然,如果当前线程池中的线程数<corePoolSize,线程是不会因为空闲而关闭的
  • workQueue:任务队列,用于存储要执行的任务。要求传入BlockingQueue接口的实现类,如ArrayBlockingQueue等
  • threadFactory:用于创建线程的工厂,我们可以通过自定义threadFactory统一为线程设置一些属性,如线程名称等。
  • handler:拒绝策略,都是RejectedExecutionHandler 的实现。线程池中已经爆满,但又有新的任务提交过来,这个时候应该执行的策略。

java线程池提供的拒绝策略有如下几种:

RejectedExecutionHandler 特点
AbortPolicy直接抛出RejectedExecutionException异常
DiscardPolicy不做任何处理,直接忽略掉这个任务
DiscardOldestPolicy将最早入队的任务移除,再尝试提交任务,不断重试
CallerRunsPolicy如果提交任务失败,会由提交任务的这个线程自己来调用execute执行任务

下面来了解一下JAVA线程池工作的基本流程

  • 1.线程池刚创建的时候,里面没有任何线程,等到有任务过来的时候才会创建线程。当然也可以调用 prestartAllCoreThreads() 或者 prestartCoreThread() 方法预创建corePoolSize个线程
  • 2.调用execute()提交一个任务时,如果当前的工作线程数<corePoolSize,直接创建新的线程执行这个任务
  • 3.如果当时工作线程数量>=corePoolSize,会将任务放入任务队列中缓存
  • 4.如果队列已满,并且线程池中工作线程的数量<maximumPoolSize,还是会创建线程执行这个任务
  • 5.如果队列已满,并且线程池中的线程已达到maximumPoolSize,这个时候会执行拒绝策略,JAVA线程池默认的策略是AbortPolicy,即抛出RejectedExecutionException异常

除了以上的几个最核心的参数,ThreadPoolExecutor类中还有其它重要的属性

Java线程池中使用一个32位的int来存储线程池的状态(runState)和池中的线程数(workerCount)低29位代表线程数(5亿多),高3位代表线程池的状态。

public class ThreadPoolExecutor extends AbstractExecutorService {
    /**
     * 这个ctl就是用来保存 线程池的状态(runState) 和 线程数(workerCount) 的
     * 这里使用AtomicInteger 来保证原子操作
     * 这里的ctl的初始值其实就是-1左移29位,即3个1和29个0, 
     * 111 00000000000000000000000000000
     */
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

    // COUNT_BITS值为29,代表着低29位用于存储线程数,高3位用于存储线程池的状态
    private static final int COUNT_BITS = Integer.SIZE - 3;
    // 线程池最大的容量,值为3个 0和29个1。也就是536870911
    // 000 11111111111111111111111111111
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // 下面这5个值代表线程池的状态,存储在高3位中
    // 3个1,29个0   111 00000000000000000000000000000
    private static final int RUNNING    = -1 << COUNT_BITS;
    // 全是0  000 00000000000000000000000000000
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    // 001 00000000000000000000000000000
    private static final int STOP       =  1 << COUNT_BITS;
    // 010 00000000000000000000000000000
    private static final int TIDYING    =  2 << COUNT_BITS;
    // 011 00000000000000000000000000000
    private static final int TERMINATED =  3 << COUNT_BITS;

    // ~就是按位取反,CAPACITY按位取反得到111 00000000000000000000000000000,
    // 再和c按位与,其实就是得到高3位,代表线程池的状态
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    // CAPACITY就是000 11111111111111111111111111111,
    // 直接按位与,其实就是得到低29位,代表线程池中的线程数
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    // 按位或
    private static int ctlOf(int rs, int wc) { return rs | wc; }


    private static boolean runStateLessThan(int c, int s) {
        return c < s;
    }

    private static boolean runStateAtLeast(int c, int s) {
        return c >= s;
    }

    private static boolean isRunning(int c) {
        return c < SHUTDOWN;
    }

    private boolean compareAndIncrementWorkerCount(int expect) {
        return ctl.compareAndSet(expect, expect + 1);
    }

    private boolean compareAndDecrementWorkerCount(int expect) {
        return ctl.compareAndSet(expect, expect - 1);
    }

    private void decrementWorkerCount() {
        do {} while (! compareAndDecrementWorkerCount(ctl.get()));
    }

    /**
     * 任务队列
     */
    private final BlockingQueue<Runnable> workQueue;

    /**
     * JAVA线程池的全局锁
     */
    private final ReentrantLock mainLock = new ReentrantLock();

    /**
     * 这个HashSet用于存放线程池中所有的工作线程,
     * 只有在持有全局锁(mainLock)的前提下,才能对这个集合进行存取操作
     */
    private final HashSet<Worker> workers = new HashSet<Worker>();

    /**
     * 这个condition是用于支持awaitTermination的
     */
    private final Condition termination = mainLock.newCondition();

    /**
     * largestPoolSize记录了线程池中线程数曾经达到的最大值
     */
    private int largestPoolSize;

    /**
     * 已完成任务的数量
     */
    private long completedTaskCount;

    /**
     * 线程工厂
     */
    private volatile ThreadFactory threadFactory;

    /**
     * 拒绝策略
     */
    private volatile RejectedExecutionHandler handler;

    /**
     * 空闲线程存活时间
     */
    private volatile long keepAliveTime;

    /**
     * 如果这个参数为true,
     * 那么核心线程数内的空闲线程 空闲时间超过keepAliveTime后,也可以被回收。
     */
    private volatile boolean allowCoreThreadTimeOut;

    /**
     * 核心线程数
     */
    private volatile int corePoolSize;

    /**
     * 最大线程数
     */
    private volatile int maximumPoolSize;

    /**
     * 默认的拒绝策略为AbortPolicy
     */
    private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();
    ......
}

从源码中我们看到java线程池有5种状态

1.RUNNING
(1)状态说明:能够接收新任务,以及对已添加的任务进行处理。
(2)状态切换:线程池的初始化状态是RUNNING

2.SHUTDOWN
(1)状态说明:不接收新任务,但能处理已添加的任务。
(2)状态切换:调用线程池的shutdown()接口时,线程池由RUNNING >> SHUTDOWN

3.STOP
(1)状态说明:不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。
(2)状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) >> STOP

4.TIDYING
(1)状态说明:当所有的任务已终止,ctl记录的"任务数量"为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。
(2)状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN >> TIDYING
当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP >> TIDYING

5. TERMINATED
(1) 状态说明:线程池彻底终止,就变成TERMINATED状态。
(2) 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING >> TERMINATED

状态切换图如下:

这里写图片描述

这里的RUNNING的值是一个负数,SHUTDOWN值为0,其他状态都大于0,而且它们的值是按照RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED 的顺序依次递增的。也就是说状态为负数的时候是线程池最正常的状态

下面就要分析ThreadPoolExecutor 的核心源码了,不过在这之前,我们还需要了解ThreadPoolExecutor中一个内部类:Worker。java线程池中的线程被包装成了一个个的Worker,代表线程池中的工作线程。

    // 这里的Worker继承了AQS同时实现了Runnable
    private final class Worker
            extends AbstractQueuedSynchronizer
            implements Runnable
    {
        private static final long serialVersionUID = 6138294804551838833L;

        /** 这个才是真正执行任务的线程 */
        final Thread thread;
        /** 每个线程要执行的第一个任务,这个值可以为null,线程自己到BlokingQueue中获取任务 */
        Runnable firstTask;
        /** 记录每个线程已完成的任务数 */
        volatile long completedTasks;

        /**
         * 这个构造方法传入这个线程第一个要执行的任务,当然也可以传入null
         */
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            // firstTask赋值
            this.firstTask = firstTask;
            // 通过ThreadFactory创建新的线程,注意:这里传入的是this,代表当前的Worker对象。
            // Worker实现了Runnable所以执行任务的时候最终会调用Worker.run()
            this.thread = getThreadFactory().newThread(this);
        }

        /** 实现了Run方法,里面会调用runWorker */
        public void run() {
            runWorker(this);
        }

        // 下面这些方法都是Worker对AQS同步控制的实现了,要获取线程的执行权,需要先获取独占锁

        protected boolean isHeldExclusively() {
            return getState() != 0;
        }

        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        public void lock()        { acquire(1); }
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }

        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }

下面来分析java线程池最核心的方法:ThreadPoolExecutor.execute()

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * 这个ctl就是用来表示线程池状态和线程数的,获取他的值
         */
        int c = ctl.get();
        // 我们前面说了,workerCountOf就是获取线程池中的线程数。
        // 如果当前线程数小于corePoolSize,那么添加一个Worker来执行任务。
        // 所以这里会开启一个新的线程,并给线程分配这个方法传入的runnable任务(command)
        if (workerCountOf(c) < corePoolSize) {
            // 如果提交任务成功,代表线程池已经接到了任务,这个时候直接return
            if (addWorker(command, true))
                return;
            // 如果提交任务失败,再次获取ctl的值
            c = ctl.get();
        }
        // 走到这里有两种情况:
        // 1.当前线程数>=corePoolSize
        // 2.上面addWorker提交任务失败了

        // 如果线程池处于RUNNING状态,将runnable任务加入到任务队列中
        // 能够进入这个分支,说明任务已经成功添加到任务队列中
        // 我们知道线程数<corePoolSize的时候,是直接开启新的线程的,
        // 但是如果线程数>=corePoolSize,任务会被添加到任务队列中。
        // 那么这个时候是否需要开启新的线程?所以这个if里面的代码就是来处理这个问题的
        if (isRunning(c) && workQueue.offer(command)) {
            // 再次获取ctl的值
            int recheck = ctl.get();
            // 如果线程池不处于RUNNING状态,那么移除这个已入队的任务,执行对应的拒绝策略
            if (! isRunning(recheck) && remove(command))
                reject(command);
            // 如果线程是处于RUNNING状态,并且当前线程池中的线程数为0,开启一个新的线程
            // 因为有可能任务添加到队列中了,但是却没有线程可执行
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        // 如果队列已满,执行addWorker尝试创建新的线程,
        // 如果成功,说明当前线程数<maximumPoolSize。
        // 如果失败,说明当前线程数已达到maximumPoolSize,需要执行拒绝策略
        else if (!addWorker(command, false))
            reject(command);
    }

这里面的addWorker方法非常重要,我们重点分析一下

    // 这个方法会创建线程并且执行任务
    // 以下几种情况这个方法会返回false:
    // 1.传入的core这个参数为true,代表线程数的上限为corePoolSize,
    //   如果当前线程数已达到corePoolSize,返回false
    // 2.传入的core这个参数为false,代表线程数的上限为maximumPoolSize,
    //   如果当前线程数已达到maximumPoolSize,返回false
    // 3.线程池stopped或者shutdown
    // 4.使用ThreadFactory创建线程失败,或者ThreadFactory返回的线程为null
    // 5.或者线程启动出现异常
    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            // 这个rs就是线程池的状态
            int rs = runStateOf(c);

            // 这里的if说的是以下3种情况,直接返回false,不会创建新的线程:
            // 1.rs大于SHUTDOWN,说明线程状态是STOP,TIDYING, 或者TERMINATED,
            //   这几种状态下,不接受新的任务,并且会中断正在执行的任务。所以直接返回false
            // 2.线程池状态处于SHUTDOWN,并且firstTask!=null。
            //   因为SHUTDOWN状态下,是不接收新的任务的。所以返回false。
            // 3.线程池处于SHUTDOWN并且firstTask为null,但是workQueue是空的。
            //   因为SHUTDOWN虽然不接收新的任务,但是已经进入workQueue的任务还是要执行的,
            //   恰巧workQueue中没有任务。所以也是返回false,不需要创建线程
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) { // 注意:这里是个for循环
                // 获取线程池中线程的数量
                int wc = workerCountOf(c);
                // 这里传入的core为true代表线程数上限为corePoolSize,
                // false代表线程数上限为maximumPoolSize,如果线程数超出上限,直接返回false
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                // 使用CAS对线程计数+1,如果成功,说明已经满足创建线程的条件了
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                // 如果上面的CAS失败,说明有并发,再次获取ctl的值
                c = ctl.get();  // Re-read ctl
                // 如果线程池的状态发生了变化,例如线程池已经关闭了,
                // 导致的CAS失败,那么回到外层的for循环(retry)
                // 否则,说明是正常的CAS失败,这个时候进入里面的循环
                if (runStateOf(c) != rs)
                    continue retry;
                
            }
        }

        // 能到这里,说明已经做好创建线程的准备了

        // worker是否已经启动的标志位
        boolean workerStarted = false;
        // 我们前面说了workers这个HashSet用于存储线程池中的所有线程,
        // 所以这个变量是代表当前worker是否已经存放到workers这个HashSet中
        boolean workerAdded = false;
        Worker w = null;
        try {
            // 传入firstTask这个任务构造一个Worker
            w = new Worker(firstTask);
            // Worker的构造方法中会使用ThreadFactory创建新的线程,
            // 所以这里可以直接获取到对应的线程
            final Thread t = w.thread;
            // 如果创建线程成功
            if (t != null) {
                
                final ReentrantLock mainLock = this.mainLock;
                // 获取线程池的全局锁,下面涉及线程池的操作都需要在持有全局锁的前提下进行
                mainLock.lock();
                try {
                    // 获取线程池的状态
                    int rs = runStateOf(ctl.get());
                    // 如果rs<SHUTDOWN,说明线程池处于RUNNING状态
                    // 或者 线程池处于SHUTDOWN状态并且没有新的任务
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        // 如果线程已经启动,抛出异常
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        // 将包装线程的worker加入到workers这个HashSet中
                        workers.add(w);
                        int s = workers.size();
                        // 我们前面说了,largestPoolSize记录的是线程池中线程数曾经到达的最大值
                        // 线程池中worker的数量是会变化的,所以记录下worker数的最大值
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        // 修改标志,代表当前worker已经加入到workers这个HashSet中
                        workerAdded = true;
                    }
                } finally {
                    // 释放全局锁
                    mainLock.unlock();
                }
                // 如果worker添加成功,启动线程执行任务
                if (workerAdded) {
                    // 启动线程
                    t.start();
                    // 代表worker已经启动
                    workerStarted = true;
                }
            }
        } finally {
            // 如果线程没有启动,这里还需要进行一些清理工作
            if (! workerStarted)
                addWorkerFailed(w);
        }
        // 返回线程是否成功启动
        return workerStarted;
    }

    // 这个方法做下面几件事:
    // 1.将worker从workers中移除
    // 2.worker的数量-1
    // 3.检查termination
    private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        // 要操作workers这个HashSet,先获取java线程池全局锁
        mainLock.lock();
        try {
            if (w != null)
                // 从worker中移除
                workers.remove(w);
            // WorkerCount -1
            decrementWorkerCount();
            // 处理TERMINATED状态
            tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }

到这里我们再回顾一下,我们调用ThreadPoolExecutor.execute()方法提交任务,要么调用addWorker添加一个新的Worker就返回了,要么不创建新的Worker,将任务放入队列中。再不然就是执行拒绝策略。而真正启动线程执行任务的操作就是在addWorker中,也就是t.start,实际上会调用Worker.run(),来看看这个方法

    public void run() {
        // 这里调用的runWorker方法
        runWorker(this);
    }
    // 这里就是执行任务的代码了,有一个while循环不断从队列中取出任务并执行,
    // 退出循环的条件是获取不到要执行的任务
    final void runWorker(Worker w) {
        // 当前线程
        Thread wt = Thread.currentThread();
        // 前面说了new Worker的时候可以指定firstTask,代表Worker的第一个任务
        Runnable task = w.firstTask;
        // 这一步就已经将firstTask置为null了
        w.firstTask = null;
        // 释放Worker的独占锁,这里它释放锁的操作一定会成功,也就是将AQS中state设置为0
        w.unlock(); // allow interrupts
        // completedAbruptly这个标志位代表当前Worker是否因为执行任务出现异常而停止的
        boolean completedAbruptly = true;

        try {
            // while循环;如果firstTask不为null那就直接执行firstTask,
            // 否则就要调用getTask()从队列中获取队列。
            // 也就是说Worker的第一个任务是不需要从队列中获取的
            while (task != null || (task = getTask()) != null) {
                // 给这个worker上独占锁
                // Worker加锁的意义在于,在线程池的其他方法中可能会中断Worker,
                // 为了保证Worker安全的完成任务,必须要在获取到锁的情况下才能中断Worker,
                // 如tryTerminate(),shutdown()等都会关闭worker。
                w.lock();
                // 如果ctl的值大于等于STOP,说明线程池的状态是STOP,TIDYING或TERMINATED。
                // 这个时候需要确保该线程已中断,否则就应该确保线程没有中断
                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,准备接受下一个任务
                    task = null;
                    // 这个worker已完成任务数+1
                    w.completedTasks++;
                    // 释放独占锁
                    w.unlock();
                }
            }
            // 到这一步说明没抛出异常
            completedAbruptly = false;
        } finally {

            // 执行到这里说明:要么队列中已经没有任务了,要么执行任务出现了异常。
            // 这个时候需要调用processWorkerExit关闭线程
            processWorkerExit(w, completedAbruptly);
        }
    }

我们再来看一下从任务队列中获取任务的方法:getTask()

    // 这个方法就是从队列中获取任务,返回null代表线程需要被关闭。一共有以下三种可能:
    // 1.阻塞获取任务直到获取成功
    // 2.获取任务超时了,也就说线程空闲了keepAliveTime这么久了,还是没有获取到任务,
    //   这个时候线程需要被关闭(这里有个前提就是线程数要大于corePoolSize)
    // 3.如果出现下面几种情况返回null,返回null说明线程需要被关闭
    //   池中worker的数量大于maximumPoolSize(由于调用setMaximumPoolSize进行了设置)
    //   线程池处于STOP状态,这个时候不能执行任务队列中的任务
    //   线程池处于SHUTDOWN状态,但是任务队列是空的
    private Runnable getTask() {
        boolean timedOut = false; // 最后一次的poll操作是否超时

        for (;;) {// for循环
            int c = ctl.get();
            // 获取线程池的状态
            int rs = runStateOf(c);

            // 如果线程池的状态大于等于STOP,或者线程池状态等于SHUTDOWN并且任务队列为空
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                // 使用CAS对workerCount-1
                decrementWorkerCount();
                // 返回null
                return null;
            }
            // 获取线程池中的线程数
            int wc = workerCountOf(c);

            // 如果allowCoreThreadTimeOut设置为true,
            // 或者线程池中线程数>corePoolSize,说明有可能发生超时
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
            // 如果当前线程数大于maximumPoolSize,或者超时
            // 注意:如果开发者调用了setMaximumPoolSize() 将maximumPoolSize变小了,
            // 就有可能出现当前线程数大于maximumPoolSize。
            // 这个时候多余的线程肯定是获取不到任务的,需要被关闭
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                // workerCount-1
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
            
            // 到这里,说明线程数小于maximumPoolSize等于且没有超时
            try {
                // 从任务队列中取出任务
                // 如果timed为true,调用带超时的poll方法,否则执行take方法阻塞获取任务。
                // timed这个变量的值取决于allowCoreThreadTimeOut || wc > corePoolSize
                // 其实这里说的是,如果线程池中线程数量在corePoolSize以内,
                // 且不支持回收核心线程数内的线程,这个时候线程池中的线程是不会被回收的。
                // 所以调用take方法阻塞获取任务,直到获取成功。
                // 否则的话,线程隔了keepAliveTime这么久还是获取不到任务,是需要被回收的
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                // 如果成功获取到任务,返回这个runnable任务,
                // 否则就是超时了,再进入下一轮循环的时候返回null
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

Worker.runWorker()中还有个清理Worker的方法:processWorkerExit

    // 这个方法就是清理Worker的,
    // 如果Worker执行任务时出现了异常,那么workerCount是没处理的,还需要把workerCount减回去
    private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        // 清理worker当然要获取全局锁
        mainLock.lock();
        try {
            // 线程池已完成的线程数+1
            completedTaskCount += w.completedTasks;
            // 将worker从线程池中移除
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }
        // 处理TERMINATED状态
        tryTerminate();

        int c = ctl.get();
        // 如果线程池状态是RUNNING或者SHUTDOWN
        if (runStateLessThan(c, STOP)) {
            // 并且不是因为执行任务出现异常而进入到这个方法
            if (!completedAbruptly) {
                // 如果allowedCoreThreadTimeOut为true,最小值为0,否则最小值为corePoolSize
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                // 如果允许回收核心线程数内的线程,并且任务队列不为空,至少还需要1个线程
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                // 如果线程数大于等于所需的最小线程数,这个方法就结束了
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            // 如果这个worker是由于执行任务异常而结束,或者是线程池中还有任务要执行,
            // 但却没有线程了。这个时候调用addWorker创建新的线程
            addWorker(null, false);
        }
    }

再来看看这个频繁出现的方法:tryTerminate()

    // 这个方法其实就是用来处理线程池TERMINATED状态的,
    // 线程池彻底终止就是TERMINATED状态。我们前面说了线程池处在TIDYING状态时,
    // 执行完terminated()之后,就会由 TIDYING -> TERMINATED。
    // 可能会引起线程池终止的操作都需要调用这个方法,
    // 例如减少worker的数量或者在shutdown期间从任务队列移除任务。
    final void tryTerminate() {
        for (;;) {// 循环执行
            int c = ctl.get();
            // 满足以下三个条件之下,直接return:
            // 1.线程池处于RUNNING状态,说明线程池正常
            // 2.线程池已经处于TERMINATED状态,就没必要继续往下走就
            // 3.线程池处于SHUTDOWN状态,并且任务队列不为空。那还是得执行玩任务
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;

            // 能到这一步说明这个时候线程池需要被终止

            // 如果这个时候worker的数量不为0
            if (workerCountOf(c) != 0) { // Eligible to terminate
                // 关闭一个worker,以确保shutdown 信号的传播
                // 调用这个方法会终止正在等待获取任务的线程。
                // 我这个线程池都要终止了,居然还有线程在等待获取任务。这当然不行。
                interruptIdleWorkers(ONLY_ONE);
                // 然后就直接return了
                return;
            }
            // 到这一步说明线程池worker和任务都清空了
            final ReentrantLock mainLock = this.mainLock;
            // 还是要获取全局锁
            mainLock.lock();
            try {
                // CAS尝试将线程状态转换成TIDYING
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        // 如果上面的CAS成功,执行terminated()。
                        // 这也是个钩子方法,留给子类实现的
                        terminated();
                    } finally {
                        // 执行完terminated()之后,最终将线程池状态置为TERMINATED
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

    // 这个方法其实就是用来中断正在等待任务的线程,
    // 注意这里说的中断其实也只是将线程的状态置为“中断”,并不是说线程在这里就真的停止了
    // 如果onlyOne为true,这里最多会关闭一个worker,因为shutdown()方法需要中断所有的worker,
    // 这里中断一个worker能够帮助shutdown迅速的完成,而不用等待一些还在等待任务的worker结束
    private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        // 一样要获取全局锁
        mainLock.lock();
        try {
            // 遍历所有的Worker,如果传入的onlyOne为true,那最多会终止一个Worker。
            // 如果传入的onlyOne为false,终止所有的Worker
            for (Worker w : workers) {
                Thread t = w.thread;
                // 这里要获取到worker的独占锁后才能够中断线程
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }

到这里整个execute方法分析完毕了,我们再来看一下线程池的关闭:shutdown()和shutdownNow()。先看下shutdown的源码

    // 关闭线程池,这个方法会中断没有执行任务的线程
    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            // 采用CAS自璇的方式将线程池状态设置为SHUTDOWN
            advanceRunState(SHUTDOWN);
            // 中断所有没有执行任务的线程
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }

        // 线程池关闭处理
        tryTerminate();
    }

    private void interruptIdleWorkers() {
        // 这里调用的是interruptIdleWorkers(false),
        // 前面说了这个方法传入true,代表中断一个没有执行任务的线程。
        // 这里是false,说明是中断所有没有执行任务的线程
        interruptIdleWorkers(false);
    }

再来看shutdownNow()方法

    // 关闭线程池。这个方法会中断所有的线程,不管线程是否正在执行任务
    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            // 采用CAS自旋的方式将线程池状态设置为STOP
            advanceRunState(STOP);
            // 中断所有线程
            interruptWorkers();
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

代码中shutdown和shutdowNow最关键的不同处在于中断线程的操作

    private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
                Thread t = w.thread;
                // 这里要获取到worker的独占锁后才能够中断线程
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }

    private void interruptWorkers() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 直接粗暴中断所有线程
            for (Worker w : workers)
                w.interruptIfStarted();
        } finally {
            mainLock.unlock();
        }
    }

我们前面说了,线程在拿到任务的时候开始执行的时候,是会获取Worker独占锁的。shutdown()方法中断worker会先调用Worker.tryLock()获取独占锁,如果线程正在执行任务,那就获取不到独占锁,也就无法中断线程。
shutdownNow()方法是直接中断所有线程

除此之外,还有个不同点在于shutdown会先将线程池状态设置为SHUTDOWN,而shutdownNow是将线程池状态设置为STOP

不管是shutdownshutdownNow或者前面的tryTerminate,它们所谓的中断线程,都只是调用Thread.interrupt()方法给线程设置interrupt标记,所以只有响应中断的任务在interrupt()以后才会终止,如BlockingQueue.take()方法

总结

整篇文章篇幅实在太长,最后不得不总结一番

1.线程池什么时候会执行拒绝策略?
    我们从源码中看到有两处地方:

  • 任务成功入队,但是线程池关闭了,并且线程池并没有移除掉这个任务,这个时候执行拒绝策。也就是说任务入队线程池关闭并发执行了
  • 当前线程数达到maximumPoolSize

2.java线程池的属性各个属性分别有什么作用?

  • corePoolSize:核心线程数
  • maximumPoolSize:线程池最大线程数
  • keepAliveTime:空闲线程存活的时间,如果线程空闲了keepAliveTime这么久以后,还是没有任务分配给它,那么线程会被关闭。当然,如果当前线程池中的线程数<corePoolSize,线程是不会因为空闲而关闭的
  • workQueue:任务队列,用于存储要执行的任务。要求传入BlockingQueue接口的实现类,如ArrayBlockingQueue等
  • threadFactory:用于创建线程的工厂,我们可以通过自定义threadFactory统一为线程设置一些属性,如线程名称等。
  • handler:拒绝策略,都是RejectedExecutionHandler 的实现。线程池中已经爆满,但又有新的任务提交过来,这个时候应该执行的策略。

3.java线程池创建线程的流程

  • 1.线程池刚创建的时候,里面没有任何线程,等到有任务过来的时候才会创建线程。当然也可以调用 prestartAllCoreThreads() 或者 prestartCoreThread() 方法预创建corePoolSize个线程
  • 2.调用execute()提交一个任务时,如果当前的工作线程数<corePoolSize,直接创建新的线程执行这个任务
  • 3.如果当时工作线程数量>=corePoolSize,会将任务放入任务队列中缓存
  • 4.如果队列已满,并且线程池中工作线程的数量<maximumPoolSize,还是会创建线程执行这个任务
  • 5.如果队列已满,并且线程池中的线程已达到maximumPoolSize,这个时候会执行拒绝策略,JAVA线程池默认的策略是AbortPolicy,即抛出RejectedExecutionException异常

4.线程池是怎么实现线程复用的?

答案在runWorker方法中,一个线程执行完一个任务后会不断从任务队列中取出任务来执行,如果队列中已经没有任务了,allowCoreThreadTimeOut设置为false并且线程数<=corePoolSize,调用BlokingQueue.take()方法阻塞,直到获取到任务
如果队列中没有任务了,allowCoreThreadTimeOut设置为true或者线程数>corePoolSize,调用BlockingQueue带超时的poll方法尝试获取任务,获取不到的话,这个线程就会被回收掉

5.线程执行任务过程中出现异常是怎么处理的?

如果一个线程执行任务出现异常,那么执行任务的线程会被关闭,而不会继续执行其他任务。最后会启动一个新的线程来取代它。

 

 

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值