Java线程池源码分析

为什么要使用线程池?

  1. 降低资源消耗:通过重复使用已经创建的线程,降低线程创建和销毁的系统开销。
  2. 提高执行效率:当任务到达时,任务不需要等待线程创建就可以执行。
  3. 提高线程的管理性:线程是稀缺资源,如果不加限制的创建,将会极大的消耗系统资源,严重时还会导致系统宕机。

ThreadPoolExecutor线程池构造方法的参数有哪些?

/**
 * 设置初始化参数创建一个新的ThreadPoolExecutor线程池
 * 参数:corePoolSize 核心线程数,无论线程池中的线程处于空闲还是运行状态,线程都将存活
 *      maximumPoolSize 最大线程数,线程池所容纳的最大线程数
 *      keepAliveTime 空闲线程最大存活时间,当线程数大于核心数时,这是多余空闲线程在终止前等待新任务的最长时间
 *      unit 空闲线程存活时间的单位
 *      workQueue 线程等待队列,用于保存由executor方法提交的执行前的任务
 *      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)
        // 核心线程数不能小于0,最大线程数不能小于等于0,最小线程数不能小于核心线程数,空闲线程存活时间不能小于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;
}

线程池的五种状态描述

线程池中有五种状态

五种状态分别是RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED

RUNNING: 在RUNNING状态下,线程池可以接收新的任务和执行已添加的任务。

SHUTDOWN: 线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。

STOP: 线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在执行的任务。

TIDYING: 当所有线程已终止,记录的线程数为0时,线程池会变成TIDYING状态。当线程池变成TIDYING状态时,会执行钩子函数terminated()。

TERMINATED: 当钩子函数terminated()被执行完成之后,线程池彻底终止,就会变成TERMINATED。

五种状态之间的相互转换

// 位数,32 - 3 = 29
private static final int COUNT_BITS = Integer.SIZE - 3;
// 线程池容量大小 capacity = 1 * 2^29 - 1,转成二进制为 00011111 11111111 11111111 11111111
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits
// 线程的运行状态 RUNNING = -1 * 2^29    转成二进制为 11100000 00000000 00000000 00000000
private static final int RUNNING    = -1 << COUNT_BITS;
// 线程的关闭状态 SHUTDOWN = 0 * 2^29    转成二进制为 00000000 00000000 00000000 00000000
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// 线程的停止状态 STOP = 1 * 2^29        转成二进制为 00100000 00000000 00000000 00000000
private static final int STOP       =  1 << COUNT_BITS;
// 线程的运行状态 TIDYING = 2 * 2^29     转成二进制为 01000000 00000000 00000000 00000000
private static final int TIDYING    =  2 << COUNT_BITS;
// 线程的结束状态 TERMINATED = 3 * 2^29  转成二进制为 01100000 00000000 00000000 00000000
private static final int TERMINATED =  3 << COUNT_BITS;

说明:线程池中的线程状态由32位中高3位表示。

ThreadPoolExecutor源码分析

executor()方法

/**
 *
 */
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    // 判断当前的线程数是否小于corePoolSize如果是,使用入参任务通过addWord方法创建一个 
    // 新的线程,如果能完成新线程创建exexute方法结束,成功提交任务
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 在第一步没有完成任务提交;状态为运行并且能成功加入任务到工作队列后,
    // 再进行一次check,如果状态在任务加入队列后变为了非运行(有可能是在执行到这里线程池shutdown了),非运行状态下当然是需要reject;
    // 否则判断当前线程数是否为0(有可能这个时候线程数变为了0),如果是则新增一个null线程,始终保证线程池中有一个线程处于运行状态;
    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);
    }
    // 如果不能加入任务到工作队列,将尝试使用任务新增一个线程,如果失败,则是线程池已经 
    // shutdown或者线程池已经达到饱和状态,所以reject; 
    else if (!addWorker(command, false))
        reject(command);
}

说明:拒绝策略不仅仅是在饱和状态下使用,在线程池进入到关闭阶段同样需要使用到;

addWorker()方法

/**
 * 新增一个任务
 */ 
private boolean addWorker(Runnable firstTask, boolean core) {
    retry: // 重试机制,类似于goto
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            // 线程池状态为非运行时状态,并且是非SHUTDOWN状态且任务为空,且阻塞队列不为空时,则不再新增线程。
            return false;

        for (;;) {
            // 获取工作线程数
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                // 当前工作线程数大于最大值
                // 或者 判断当前线程是否是核心线程,若是核心线程则判断当前线程数是否大于等于corePoolSize;若非核心线程则判断当前线程数是否大于等于maximumPoolSize
                // 若是则不再新增线程
                return false;
            if (compareAndIncrementWorkerCount(c))
                // 工作线程数量 ctl+1,如果成功,则跳出循环。compareAndIncrementWorkerCount()方法中使用了CAS原子操作。
                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 {
        // 内部类Worker,继承了AQS,封装了线程和任务的管理方法,通过threadfactory创建线程
        w = new Worker(firstTask);
        final Thread t = w.thread;
        // 线程创建成功
        if (t != null) {
            // 获取独占锁ReentrantLock            
            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());
                // 若是当前线程正在运行中,或者当前线程处于SHUTDOWN状态,且当前任务为空时
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    // 判断但前线程是否存活,若是存活则直接抛出异常,因为此时线程尚未start
                    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独占锁
                mainLock.unlock();
            }
            if (workerAdded) {
                // 线程添加成功之后,启动线程
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            // 失败回退 从wokers移除w 线程数减1 尝试结束线程池
            addWorkerFailed(w);
    }
    return workerStarted;
}

线程池中的拒绝策略

线程池中有4种拒绝策略,分别是AbortPolicy,DiscardPolicy,DiscardOldestPolicy,CallerRunsPolicy

AbortPolicy策略

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());
    }
}

DiscardPolicy策略

public static class DiscardPolicy implements RejectedExecutionHandler {
    /**
     * Creates a {@code DiscardPolicy}.
     */
    public DiscardPolicy() { }

    /**
     * Does nothing, which has the effect of discarding task r.
     * 当线程池无法接受新的任务时,将该任务直接丢弃,不做任何提示
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
}

DiscardOldestPolicy策略

public static class DiscardOldestPolicy implements RejectedExecutionHandler {
    /**
     * Creates a {@code DiscardOldestPolicy} for the given executor.
     */
    public DiscardOldestPolicy() { }

    /**
     * Obtains and ignores the next task that the executor
     * would otherwise execute, if one is immediately available,
     * and then retries execution of task r, unless the executor
     * is shut down, in which case task r is instead discarded.
     * 在线程池未关闭的状态下,丢弃线程队列中的第一个线程,然后添加当前线程
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            e.getQueue().poll();
            e.execute(r);
        }
    }
}

CallerRunsPolicy策略

public static class CallerRunsPolicy implements RejectedExecutionHandler {
    /**
     * Creates a {@code CallerRunsPolicy}.
     */
    public CallerRunsPolicy() { }

    /**
     * Executes task r in the caller's thread, unless the executor
     * has been shut down, in which case the task is discarded.
     * 当线程池处于未关闭状态,并且无法接受新任务时,用当前提交任务的线程来处理提交的任务,保证线程不丢失。
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            r.run();
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值