线程池介绍

线程池就是用来装线程的池子,简直太形象了。在Java中经常接触到的是ThreadPoolExecutor,查看源码知道ThreadPoolExecutor其实继承了抽象类AbstractExecutorService,然后AbstractExecutorService又实现了ExecutorService接口,而ExecutorService又是继承了Executor接口,所以Java线程池的基础就先分别介绍这几个重要的类和接口。

ThreadPoolExecutor

线程池允许多个线程同时运行,允许同时运行的线程数量就是线程池的容量;当添加的到线程池中的线程超过它的容量时,会有一部分线程阻塞等待。线程池会通过相应的调度策略和拒绝策略,对添加到线程池中的线程进行管理。

ThreadPoolExecutor简单使用
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            executor.execute(new Runnable() {

                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());                   
                }
            });
        }

        executor.shutdown();

上面简单演示了ThreadPoolExecutor的创建,添加任务和终止线程。

下面先通过源码整理出它里面重要的api方法和变量:

//阻塞线程队列
private final BlockingQueue<Runnable> workQueue;
//互斥锁
private final ReentrantLock mainLock = new ReentrantLock();
//线程集合
private final HashSet<Worker> workers = new HashSet<>();
//mainLock的终止条件
private final Condition termination = mainLock.newCondition();
//线程池达到过的最大值
private int largestPoolSize;
//已完成任务数
private long completedTaskCount;
//用于构建一个新线程
private volatile ThreadFactory threadFactory;
//拒绝执行handler
private volatile RejectedExecutionHandler handler;
//存活时间
private volatile long keepAliveTime;
//是否允许核心线程暂停
private volatile boolean allowCoreThreadTimeOut;
//核心线程池大小
private volatile int corePoolSize;
//实际线程池最大值,受线程池容量影响
private volatile int maximumPoolSize;



/**
 * ThreadPoolExecutor有四个构造函数,这里介绍参数最多的一个
 *corePoolSize:核心线程池大小
 *maximumPoolSize:最大线程池大小
 *keepAliveTime:保持线程存活时间
 *unit:
 *workQueue:阻塞队列
 *threadFactory:用于创建线程
 *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;
    }



    public void execute(Runnable command)


    public void shutdown()


    public List<Runnable> shutdownNow() 


    public boolean isShutdown()

    public boolean isTerminating()

    public boolean isTerminated()


    public boolean awaitTermination(long timeout, TimeUnit unit)


    public void setThreadFactory(ThreadFactory threadFactory)


    public ThreadFactory getThreadFactory()

    public void setRejectedExecutionHandler(RejectedExecutionHandler handler)

    public RejectedExecutionHandler getRejectedExecutionHandler()


    public void setCorePoolSize(int corePoolSize)


    public int getCorePoolSize()

    public boolean prestartCoreThread()

    void ensurePrestart()

    public int prestartAllCoreThreads()

    public void setMaximumPoolSize(int maximumPoolSize)

    public int getMaximumPoolSize()

    public void setKeepAliveTime(long time, TimeUnit unit)

    public long getKeepAliveTime(TimeUnit unit)

    public BlockingQueue<Runnable> getQueue()

    public boolean remove(Runnable task)

    public void purge()

    public int getPoolSize()

    public int getActiveCount()

    public int getLargestPoolSize()

    public long getTaskCount()

    public long getCompletedTaskCount()
线程池生命周期

首先要介绍的是clt,它包含两方面

workerCount,当前有效的线程数量;

表示已经被允许执行 但不允许倍停止的线程数量,但它不一定等于存活的线程数。

runState,表示当前线程池的状态,

runState一共有五种状态,分别为:

RUNNING: 允许创建新任务和执行queued中的任务

SHUTDOWN:不能创建新任务,但可以执行queued中的任务

STOP:不能创建新任务,不能执行queued中的任务,并且中断正在执行的任务

TIDYING:所有任务被终止,workCount变为0,并且会调用terminated()方法

TERMINATED:terminated()执行完成

重要实现方法

下面在看一下它内部的实现和重要的方法,
首先看一下最重要的execute方法:

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();

        int c = ctl.get();
        //如果工作的线程数小于核心线程池大小
        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);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

分析一下上面的代码,总共分为三步:
1、当提交一个任务时,如果工作的线程数小于核心线程池大小时就直接新建一个线程执行任务
2、如果工作的线程数大于了核心线程池大小,新提交的任务会被放入workQueue,等待线程池调度
3、如果线程数已经大于了最大线程池大小,就会调用reject方法,拒绝任务。

下面这个方法addWorker是将一个任务添加到线程池:

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

        // 如果工作队列为空返回添加失败
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        //循环遍历
        for (;;) {
            int wc = workerCountOf(c);
            //如果工作的线程数超过了容量或者核心线程池大小返回添加失败
            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,一个Worker对应一个线程
    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;
}
终止线程

终止线程的方法有shutdown和shutdownNow

public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //检测是否有执行的权限
            checkShutdownAccess();
            //将状态设置为SHUTDOWN,
            advanceRunState(SHUTDOWN);
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }

shutdownNow的代码如下:

public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            //将状态设置为STOP,
            advanceRunState(STOP);
            //中断所有线程
            interruptWorkers();
            //清空所有的workQueue
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

上面的drainQueue方法:

private List<Runnable> drainQueue() {
        BlockingQueue<Runnable> q = workQueue;
        ArrayList<Runnable> taskList = new ArrayList<>();
        q.drainTo(taskList);
        //将q中的所有元素清空,并添加到taskList中
        if (!q.isEmpty()) {
            for (Runnable r : q.toArray(new Runnable[0])) {
                if (q.remove(r))
                    taskList.add(r);
            }
        }
        return taskList;
    }

shutdow 和shutdownNow的区别:
shutdown是将runState设置为SHURDOWN,然后中断空闲的线程
shutdownNow是将状态设置为STOP,并中断所有线程,最后还清空了workQueue.

中断线程空闲的线程

private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //遍历所有Worker,并且中断线程
            for (Worker w : workers) {
                Thread t = w.thread;
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }

至此已经总结了线程池的构造方法,通过execute方法提交任务,通过shutdown和shutdownNow方法终止线程。