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