【并发】ThreadPoolExecutor

简介

ThreadPoolExecutorExecutor接口的实现类,Executors类的newFixedThreadPool等方法创建的正是ThreadPoolExecutor实例。

线程池流程
  1. 如果线程池当前线程数小于corePoolSize,则会创建新线程处理请求,即使当前有空闲线程;
  2. 如果当前线程数大于等于corePoolSize,小于maximunPoolSize,将当前请求放入阻塞队列,如果队列已满才会新建线程处理请求;
  3. 如果线程数已经大于maximunPoolSize,则根据配置的拒绝策略进行处理。
Keep-Alive Time

如果线程池当前线程数大于corePoolSize,此时空闲时间大于keepAliveTime的线程将会被终止。默认情况下,keep-alive策略仅仅针对线程数大于corePoolSize的情况,通过allowCoreThreadTimeOut(boolean)方法可以指定作用于core thread

队列类型
SynchronousQueue

SynchronousQueue是一个不存储元素的阻塞队列,每一个put操作必须等待一个take操作,否则不能继续添加元素。

如果当前没有空闲线程可以立即处理请求,则入队失败,此时会创建一个新线程处理该请求,但是使用该队列一般需要配置无界的maximumPoolSizes,避免可能交由拒绝策略进行处理的情况。

无界队列

例如没有指定大小的LinkedBlockingQueue,使用无界队列时,如果当前所有的corePoolSize线程正在处理请求时,新的请求过来就会进入阻塞队列中进行等待,因此线程池中最多只有coreSize个线程,此时maximumPoolSize没有任何影响。

此种队列适合每一个请求是相互独立的,请求执行时互不影响。例如在web page server中,此种队列可以进行流量削峰。

有界队列

例如ArrayBlockingQueue,在使用此种队列的情况下,通过指定有界的maximumPoolSizes可以避免资源耗尽的情况。

拒绝策略
  • AbortPolicy:默认策略,抛出RejectedExecutionException异常;
  • CallerRunsPolicy:在调用execute的线程中运行任务;
  • DiscardPolicy:将任务丢弃;
  • DiscardOldestPolicy:将队列头的任务丢弃。
钩子方法

通过重写beforeExecute(Thread, Runnable)afterExecute(Runnable, Throwable)可以进行类似拦截器的操作。

数据结构

ThreadPoolExecutor 核心属性

ctl变量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

private static int ctlOf(int rs, int wc) { 
    return rs | wc; 
}

ctl变量是线程池的控制状态,本身是一个原子整型,包含了两个核心概念:

  • workerCount: 表示当前线程池有效的线程数量;
  • runState: 表示线程池的状态,运行中、关闭等。

runState提供线程池生命周期的控制,具体如下:

  • RUNNING: 可以接收新任务和处理队列中任务;
  • SHUTDOWN: 不能接收新任务,但是会继续处理完队列中的任务;
  • STOP: 不能接收新任务,无法处理队列中的任务,甚至中断运行中的任务;
  • TIDYING: 所有任务已经结束,workCount为0,转换到状态TIDYING的线程将运行terminate钩子方法;
  • TERMINATED: terminated方法执行结束。

生命周期状态转换如下:

  • RUNNING -> SHUTDOWN : 调用了shutdown()方法;
  • (RUNNING or SHUTDOWN) -> STOP : 调用了shutdownNow()方法;
  • SHUTDOWN -> TIDYING : 队列和线程池都为空;
  • STOP -> TIDYING: 线程池为空;
  • TIDYING -> TERMINATED : 钩子方法terminated()执行完毕。因awaitTermination为阻塞的线程会返回,当线程池状态变为TERMINATED时。

生命周期状态源码如下:

private static final int COUNT_BITS = Integer.SIZE - 3;  //29
private static final int CAPACITY   = (1 << COUNT_BITS) - 1; //536870911

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS; //-536870912
private static final int SHUTDOWN   =  0 << COUNT_BITS; //0
private static final int STOP       =  1 << COUNT_BITS; //536870912
private static final int TIDYING    =  2 << COUNT_BITS; //1073741824
private static final int TERMINATED =  3 << COUNT_BITS; //1610612736

//判断线程池是否运行状态
private static boolean isRunning(int c) {
    return c < SHUTDOWN;
}
其他核心属性
//工作队列,即阻塞队列
private final BlockingQueue<Runnable> workQueue;
//互斥锁
private final ReentrantLock mainLock = new ReentrantLock();
//线程池中所有的工作线程
private final HashSet<Worker> workers = new HashSet<Worker>();
//支持awaitTermination的等待条件
private final Condition termination = mainLock.newCondition();
//
private int largestPoolSize;
//已结束任务的数量
private long completedTaskCount;

/**
 * 所有由用户控制的参数都声明为volatile变量
 */

//创建线程的线程工厂
private volatile ThreadFactory threadFactory;
//拒绝策略处理器
private volatile RejectedExecutionHandler handler;
//等待任务的空闲线程的存活时间(纳秒级别)。默认情况下,只有线程数量超过corePoolSize时,该配置才会生效
private volatile long keepAliveTime;
//`core thread`是否会超时回收,默认为false
private volatile boolean allowCoreThreadTimeOut;
//默认情况下,线程池中的最小线程数量,当设置allowCoreThreadTimeOut时,最小数量为0
private volatile int corePoolSize;
//最大线程数量
private volatile int maximumPoolSize;
//默认拒绝策略为AbortPolicy
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

Worker 核心属性

Worker类是ThreadPoolExecutor的内部类,继承了AQS,即是一个同步器,同时实现了Runnable接口。

final Thread thread;
//创建时的初始化任务,任务执行后置为空,后续Worker从阻塞队列中获取任务
Runnable firstTask;
//已完成任务数
volatile long completedTasks;

Worker方法详解

构造函数
Worker(Runnable firstTask) {
    //设置共享变量
    setState(-1); 
    this.firstTask = firstTask;
    //新建线程
    this.thread = getThreadFactory().newThread(this);
}
运行方法
public void run() {
    //执行ThreadPoolExecutor的方法,稍后详解
    runWorker(this);
}
同步器方法
isHeldExclusively()
//state为0表示无锁状态,为1表示锁住状态
protected boolean isHeldExclusively() {
    return getState() != 0;
}
tryAcquire(int)
protected boolean tryAcquire(int unused) {
    //使用CAS方法尝试加锁
    //加锁成功设置当前线程为锁的持有者,并返回true
    //加锁失败返回false
    if (compareAndSetState(0, 1)) {
        setExclusiveOwnerThread(Thread.currentThread());
        return true;
    }
    return false;
}
tryRelease(int)
protected boolean tryRelease(int unused) {
    //将锁的持有者置为空,并将共享状态置为0
    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) {
        }
    }
}

方法详解

一. 构造函数

ThreadPoolExecutor总共有4个构造函数,阿里规约推荐我们使用原生的构造函数创建线程池,而不是使用Executors工厂方法。

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.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;
}
二. 提交任务

我们通常会使用ThreadPoolExecutorsubmit(Runnable)方法来提交任务,而该方法内部主要是通过execute(Runnable)方法来实现。

execute(Runnable)方法主要用来执行任务,任务可能通过新线程执行,也可能是线程池中现有空闲线程执行。

如果因为线程池shutdown或者线程数已达上限,而导致任务无法执行,则该任务会交由RejectedExecutionHandler处理。

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    //workerCountOf(c)方法获取到workerCount
    //情况1: workerCount小于corePoolSize,则新增线程处理
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    //情况2: 当前线程池处于RUNNING状态,并且入队成功
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        //双重检查,如果此时线程池关闭并且出队成功,则交由RejectedExecutionHandler处理
        if (!isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    //情况3: 如果入队失败,则尝试新增线程处理,如果新增失败,则交由RejectedExecutionHandler处理
    else if (!addWorker(command, false))
        reject(command);
addWorker(Runnable, boolean)

addWorker方法主要完成如下工作:

  1. 新建Worker并加入workers集合中,并使用CAS为workCount加1;
  2. 启动Worker线程,执行runWorker方法;
  3. 如果添加Worker失败,将Worker从workers集合中移除,并将workCount减1
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        //获取runState
        int rs = runStateOf(c);

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

        for (;;) {
            //获取workerCount
            int wc = workerCountOf(c);
            //大于容量不创建新任务
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            //使用CAS方法增加workCount的数量
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  
            if (runStateOf(c) != rs)
                continue retry;
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    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();
                    //将任务加入到worker集合中
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                //启动线程,执行runWorker方法
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}
runWorker(Worker)

Worker线程的run()执行该方法,通过自旋处理firstTask或者阻塞队列里面的任务

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    // allow interrupts
    w.unlock(); 
    boolean completedAbruptly = true;
    try {
        //任务为空时,从阻塞队列中获取任务,循环直到队列为空
        while (task != null || (task = getTask()) != null) {
            // 如果拿到了任务,给自己上锁,表示当前Worker已经要开始执行任务了,已经不是闲置Worker
            // getActiveCount返回正在执行的worker线程数量,正是通过worker的isLocked方法来判断
            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
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                //钩子方法,子类可以重写实现拦截功能
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                // 真正的开始执行任务,调用的是run方法,而不是start方法。这里run的时候可能会被中断,比如线程池调用了shutdownNow方法
                    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;
                // 记录执行任务的个数
                w.completedTasks++;
                // 执行完任务之后,解锁,Worker变成闲置Worker
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

ThreadPoolExecutor提交任务的大体流程如下:

  1. 如果workerCount小于corePoolSize,则新增worker线程处理,任务处理完毕后,后续worker线程从阻塞队列中获取任务执行;
  2. 如果workerCount大于等于corePoolSize,则将新任务加入阻塞队列中,如果加入失败(例如队列已满),则尝试新增线程处理,如果新增线程失败(例如线程数已大于等于maximumPoolSize),则交由拒绝策略处理器RejectedExecutionHandler处理。
  3. 执行完初始任务的worker线程会自旋获取阻塞队列中的任务。如果线程池当前线程数大于corePoolSize,此时空闲时间大于keepAliveTime的线程将会被终止。默认情况下,keep-alive策略仅仅针对线程数大于corePoolSize的情况,通过allowCoreThreadTimeOut(boolean)方法可以指定作用于core thread
三. 线程池关闭
(1) shutdown()

调用shutdown()方法之后,线程池不会接受新的任务请求,但已有的任务会执行完毕。

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        //更新ctl变量,rs更新为SHUTDOWN状态,ws为现有worker线程数量
        advanceRunState(SHUTDOWN);
        interruptIdleWorkers();
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
}
tryTerminate()
final void tryTerminate() {
    for (;;) {
        //获取线程池状态
        int c = ctl.get();
        //当前线程池处于以下三种状态则返回:
        //1.线程池还处于运行状态;
        //2.线程池还处于TIDYING状态或TIDYING之前的状态
        //3.线程池处于SHUTDOWN状态,但是工作队列还有任务,这也就意味着该方法会等待工作队列中的任务执行完毕
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        //进行线程中断
        if (workerCountOf(c) != 0) { // Eligible to terminate
            interruptIdleWorkers(ONLY_ONE);
            return;
        }

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //更新tcl的rs为TIDYING,ws为0
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    //protected空方法,由子类实现自定义逻辑
                    terminated();
                } finally {
                    //更新tcl的rs为TERMINATED
                    ctl.set(ctlOf(TERMINATED, 0));
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}
(2) shutdownNow()

shutdownNow()会尝试停止所有正在执行的任务,暂停正在等待执行的任务的处理,并返回正在等待执行的任务的列表。

public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        //直接将线程池状态更新为STOP,绕过了tryTerminate的判定校验
        advanceRunState(STOP);
        interruptWorkers();
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadPoolExecutor是Java中的一个线程池实现类,它可以用来管理和调度多个线程执行任务。通过使用ThreadPoolExecutor,我们可以有效地控制并发任务的执行。 当我们向ThreadPoolExecutor提交任务时,它会根据配置的参数来管理线程的创建和销毁,并且将任务分配给空闲的线程进行执行。以下是ThreadPoolExecutor提交任务的过程: 1. 创建ThreadPoolExecutor对象:首先,我们需要创建一个ThreadPoolExecutor对象,并指定线程池的大小、任务队列的容量、线程的生命周期策略等参数。 2. 创建任务:我们需要创建一个实现了Runnable或Callable接口的任务对象,该任务对象封装了要执行的具体逻辑。 3. 提交任务:通过调用ThreadPoolExecutor的submit()方法,将任务提交给线程池。submit()方法会返回一个Future对象,可以用来获取任务的执行结果。 4. 线程调度:ThreadPoolExecutor会根据配置的参数来管理线程的创建和销毁。如果有空闲的线程可用,线程池会将任务分配给其中一个线程进行执行;如果所有线程都在忙碌状态,任务会被放入任务队列中等待执行。 5. 任务执行:被选中的线程会从任务队列中取出任务,并执行任务的run()方法。执行完毕后,线程会返回线程池,并准备接收下一个任务。 6. 获取任务结果:如果我们需要获取任务的执行结果,可以通过Future对象的get()方法来获取。get()方法会阻塞当前线程,直到任务执行完毕并返回结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值