ThreadPoolExecutor线程池

一、ThreadPoolExecutor的构造函数

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

构造函数的7个参数说明:

1.corePoolSize:核心线程数,默认情况下核心线程会一直存活,即使处于闲置状态也不会受存keepAliveTime限制。除非将allowCoreThreadTimeOut设置为true。
2.maximumPoolSize:线程池所能容纳的最大线程数。超过这个数的线程将被阻塞。当任务队列为没有设置大小的LinkedBlockingDeque时,这个值无效。
3.keepAliveTime:非核心线程的闲置超时时间,超过这个时间就会被回收。
4.unit:指定keepAliveTime的单位,如TimeUnit.SECONDS。当将allowCoreThreadTimeOut设置为true时对corePoolSize生效。
5.workQueue:线程池中的任务队列.常用的有三种队列
  a.SynchronousQueue:是一种无缓冲的等待队列,在某次添加元素后必须等待其他线程取走后才能继续添加;
  b.LinkedBlockingDeque:是一个无界缓存的等待队列,不指定容量则为Integer最大值,锁是分离的;
  c.ArrayBlockingQueue:是一个有界缓存的等待队列,必须指定大小,锁是没有分离的;
6.threadFactory:线程工厂,提供创建新线程的功能,通过线程工厂可以对线程的一些属性进行定制。
7.RejectedExecutionHandler:当线程池中的资源已经全部使用,添加新线程被拒绝时,会调用RejectedExecutionHandler的rejectedExecution方法,线程池有以下四种拒绝策略。
  a.AbortPolicy:当任务添加到线程池中被拒绝时,它将抛出RejectedExecutionException 异常。
  b.CallerRunsPolicy:当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。
  c.DiscardOldestPolicy:当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。
  d.DiscardPolicy:当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。

线程任务添加到线程池中的流转原理:

1.若存在空闲线程,则直接运行;
2.若不存在空闲线程,且当前线程池中的线程数少于核心线程数,则直接创建线程运行;
3.若不存在空闲线程,且当前线程池中的线程数大于核心线程数,则添加到阻塞队列;
4.若不存在空闲线程,且阻塞队列已满,并且当前线程池中的线程数小于最大线程数,则创建非核心线程运行任务;
5.若不存在空闲线程,且阻塞队列已满,并且当前线程池中的线程数等于最大线程数,则执行构造函数中的拒绝策略。
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
       
    int c = ctl.get();
    // 当前线程数小于 corePoolSize 时,调用 addWorker 创建核心线程来执行任务
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 当前线程数不小于 corePoolSize ,就将任务添加到 workQueue 中
    if (isRunning(c) && workQueue.offer(command)) {
        // 获取到当前线程的状态,赋值给 recheck ,是为了重新检查状态
        int recheck = ctl.get();
        // 如果 isRunning 返回 false ,那就 remove 掉这个任务,然后执行拒绝策略,也就是回滚重新排队
        if (! isRunning(recheck) && remove(command))
            reject(command);
        // 线程池处于 running 状态,但是没有线程,那就创建线程执行任务
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    // 如果放入 workQueue 失败,尝试通过创建非核心线程来执行任务
    // 如果还是失败,说明线程池已经关闭或者已经饱和,会拒绝执行该任务
    else if (!addWorker(command, false))
        reject(command);
}

线程池中的线程复用原理:

  主要体现在Worker类中的runWorker()方法,其中Worker类继承了AQS,实现了Runnable。可以用以线程的创建。他重写的run()方法调用了runWorker()方法,里面

有个while循环(while (task != null || (task = getTask()) != null) ),先获取线程自己的任务,自己的任务执行完成之后,则会调getTask()方法从阻塞队列中获取最新的task任务。如果得到任务,则复用worker线程执行该task任务,如果task为null,则跳出while循环,线程执行完毕进行释放。

private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable
final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        // 允许中断
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            // 判断 task 是否为空,如果不为空直接执行
            // 如果 task 为空,调用 getTask() 方法,从 workQueue 中取出新的 task 执行
            while (task != null || (task = getTask()) != null) {
                // 加锁,防止被其他线程中断
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                // 检查线程池的状态,如果线程池处于 stop 状态,则需要中断当前线程
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    // 执行 beforeExecute 
                    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 方法
                        afterExecute(task, thrown);
                    }
                } finally {
                    // 将 task 设置为 null ,循环操作
                    task = null;
                    w.completedTasks++;
                    // 释放锁
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

getTask方法

private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            // allowCoreThreadTimeOut 变量默认为 false ,也就是核心线程就算是空闲也不会被销毁
            // 如果为 true ,核心线程在 keepAliveTime 内是空闲的,就会被销毁
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            // 如果运行线程数大于最大线程数,但是缓存队列已经空了,此时递减 worker 数量
            // 如果有设置允许线程超时或者线程数量超过了核心线程数量,并且线程在规定时间内没有 poll 到任务并且队列为空,此时也递减 worker 数量
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
                // 如果 timed 为 true ,会调用 workQueue 的 poll 方法
                    // 超时时间为 keepAliveTime ,如果超过 keepAliveTime 时长的话, poll 就会返回 null 
                    // 如果返回为 null ,在 runWorker 中 
                    // while (task != null || (task = getTask()) != null) 循环条件被打破,从而跳出循环,此时线程执行完毕
                // 如果 timed 为 false ( allowCoreThreadTimeOut 为 false ,并且 wc > corePoolSize 为 false )
                    // 会调用 workQueue 的 take 方法阻塞到当前
                    // 当队列中有任务加入时,线程被唤醒, take 方法返回任务,开始执行
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

 

posted @ 2022-06-23 11:33  风缱云流  阅读(36)  评论(0编辑  收藏  举报