线程池原理

类图
Executor -> ExecutorService -> AbstractExecutorService -> ThreadPoolExecutor
线程池的主要任务是将“任务”和“线程”解偶,生产者-消费者模式

线程池状态管理

高3位保存线程池的运行状态runState,低29位保存有效线程数量workerCount

    @ReachabilitySensitive
    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;

相关计算

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; }   //通过状态和线程数生成ctl

线程池的运行状态

    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS; //能接受新的任务,也能处理阻塞队列中的任务
    private static final int SHUTDOWN   =  0 << COUNT_BITS; // 不能接受新的任务,但能继续处理阻塞队列中的任务,中断空闲线程
    private static final int STOP       =  1 << COUNT_BITS; // 不能接受新的任务,也不处理阻塞队列中的任务,会中断所有线程
    private static final int TIDYING    =  2 << COUNT_BITS; // 所有的任务都被终止了,有效线程数为0
    private static final int TERMINATED =  3 << COUNT_BITS; // 在terminated()方法执行完后进入该状态

创建线程池

newFixedThreadPool

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

newCachedThreadPool

有新任务就创建新的线程,线程空闲会被重复利用,线程空闲60s会被回收

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

newSingleThreadExecutor

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

newScheduledThreadPool

执行延时或定时任务

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

关闭线程池

shutdown

会等待阻塞队列的任务先完成,再关闭

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            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();
            advanceRunState(STOP);
			// 中断所有线程
            interruptWorkers();
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

awaitTermination

等待指定的时间让线程池关闭

任务管理

任务调度

execute方法完成

workerCount < corePoolSize

创建一个新的线程来执行新提交的任务

        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }

workCount >= corePoolSize && 阻塞队列未满

将新提交的任务添加到阻塞队列列表

if (isRunning(c) && workQueue.offer(command))

workCount >= corePoolSize && 阻塞队列已满 && workerCount < maximumPoolSize

创建并启动一个线程来执行新提交的任务

addWorker(command, false)

workerCount >= maximumuPoolSize

拒绝策略处理该任务

 else if (!addWorker(command, false))
            reject(command);

阻塞队列分类

线程池阻塞队列作用
newFixedThreadPoolLinkedBlockingQueue一个由链表结构组成的有界队列,FIFO,默认容量为Integer.MAX_VALUE
newCachedThreadPoolSynchronousQueue一个不存储元素的阻塞队列,每一个put操作,必须等待take操作,否则不能添加元素。支持公平锁和非公平锁。
newSingleThreadExecutorLinkedBlockingQueue
newScheduledThreadPoolDelayedWorkQueue数组构成的优先级队列

任务申请

  • 新创建的线程执行
  • 空闲线程获取任务执行
    主要由getTask方法实现 : runWorker -> getTask
  1. 线程池停止运行或shutdown且阻塞队列为空,返回null
            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }
  1. 线程数过多,返回null; 阻塞队列为空或获取不到任务返回null
 			int wc = workerCountOf(c);

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
  1. 限时获取任务 || 阻塞获取任务
    Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();

任务拒绝

当阻塞队列已满 && workerCount达到maximumPoolSize时,就要拒绝掉该任务。
拒绝策略是一个接口

public interface RejectedExecutionHandler {
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

四种拒绝策略

策略描述
AbortPolicy默认拒绝策略,丢弃任务并且抛出异常
DiscardPolicy丢弃任务,但不抛出异常
DiscardOldestPolicy丢弃队列最前面的任务,重新提交被拒绝的任务
CallerRunsPolicy由调用线程处理该任务

Worker线程管理

掌握线程的状态并维护线程的生命周期,继承AQS,实现独占锁,不可重入性反应线程的执行状态。

  private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
        final Thread thread; //持有的线程
        Runnable firstTask; // 第一个任务有可以为null
        volatile long completedTasks; //已完成的任务计数
  }

shutdown方法和tryTerminate方法重会去中断idle状态线程,判断线程是否处于idle状态通过Worker的tryLock方法(独占锁)

Worker线程增加

通过addWorker方法实现

线程池状态大于SHUTDOWN,则返回false

线程池状态 == SHUTDOWN && 新增加线程用于处理阻塞队列中的任务,继续下去

     // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && ! (rs == SHUTDOWN &&firstTask == null &&! workQueue.isEmpty()))
                return false;

线程数量超过限制,返回false

线程数大于容量,核心线程数,最大线程数

                int wc = workerCountOf(c);
                if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;

最后增加线程,启动线程

Worker线程回收

核心线程无线等待获取任务,非核心线程限时获取任务,线程回收由processWorkerExit方法实现

    final void runWorker(Worker w) {
     ......
        try {
            while (task != null || (task = getTask()) != null) {
              .......
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

消除自身在线程池内的引用

        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }

如果用户状态异常导致线程退出,需要判断线程池状态,重新分配线程

        int c = ctl.get();
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }

时序图:
在这里插入图片描述

参考:https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值