Java线程池ThreadPoolExecutor源码分析
1 2 3 4 5 | class DirectExecutor implements Executor{ public void execute(Runnable r){ r.run(); // 这里不是用的new Thread(r).start(),也就是说没有启动任何一个新的线程。 } } |
每个任务提交进来后,直接启动一个新的线程来执行这个任务:
1 2 3 4 5 | class ThreadPerTaskExecutor implements Executor{ public void execute(Runnable r){ new Thread(r).start(); // 每个任务都用一个新的线程来执行 } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | class SerialExecutor implements Executor { // 任务队列 final Queue<Runnable> tasks = new ArrayDeque<Runnable>(); // 这个才是真正的执行器 final Executor executor; // 当前正在执行的任务 Runnable active; // 初始化的时候,指定执行器 SerialExecutor(Executor executor) { this .executor = executor; } // 添加任务到线程池: 将任务添加到任务队列,scheduleNext 触发执行器去任务队列取任务 public synchronized void execute( final Runnable r) { tasks.offer( new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (active == null ) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((active = tasks.poll()) != null ) { // 具体的执行转给真正的执行器 executor executor.execute(active); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public interface ExecutorService extends Executor { void shutdown(); List<Runnable> shutdownNow(); boolean isShutdown(); boolean isTerminated(); boolean awaitTermination( long timeout, TimeUnit unit) throws InteruptedException; <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task); <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException; <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException; <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException; <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } |
一般我们定义一个线程池的时候,往往都是使用这个接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | public abstract class AbstractExecutorService implements ExecutorService { // RunnableFuture 是用于获取执行结果的,我们常用它的子类 FutureTask // 下面两个 newTaskFor 方法用于将我们的任务包装成 FutureTask 提交到线程池中执行 protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value); } protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return new FutureTask<T>(callable); } // 提交任务 public Future<?> submit(Runnable task) { if (task == null ) throw new NullPointerException(); // 1. 将任务包装成 FutureTask RunnableFuture<Void> ftask = newTaskFor(task, null ); // 2. 交给执行器执行,execute 方法由具体的子类来实现 // 前面也说了,FutureTask 间接实现了Runnable 接口。 execute(ftask); return ftask; } public <T> Future<T> submit(Runnable task, T result) { if (task == null ) throw new NullPointerException(); // 1. 将任务包装成 FutureTask RunnableFuture<T> ftask = newTaskFor(task, result); // 2. 交给执行器执行 execute(ftask); return ftask; } public <T> Future<T> submit(Callable<T> task) { if (task == null ) throw new NullPointerException(); // 1. 将任务包装成 FutureTask RunnableFuture<T> ftask = newTaskFor(task); // 2. 交给执行器执行 execute(ftask); return ftask; } // 此方法目的:将 tasks 集合中的任务提交到线程池执行,任意一个线程执行完后就可以结束了 // 第二个参数 timed 代表是否设置超时机制,超时时间为第三个参数, // 如果 timed 为 true,同时超时了还没有一个线程返回结果,那么抛出 TimeoutException 异常 private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks, boolean timed, long nanos) throws InterruptedException, ExecutionException, TimeoutException { if (tasks == null ) throw new NullPointerException(); // 任务数 int ntasks = tasks.size(); if (ntasks == 0 ) throw new IllegalArgumentException(); // List<Future<T>> futures= new ArrayList<Future<T>>(ntasks); // ExecutorCompletionService 不是一个真正的执行器,参数 this 才是真正的执行器 // 它对执行器进行了包装,每个任务结束后,将结果保存到内部的一个 completionQueue 队列中 // 这也是为什么这个类的名字里面有个 Completion 的原因吧。 ExecutorCompletionService<T> ecs = new ExecutorCompletionService<T>( this ); try { // 用于保存异常信息,此方法如果没有得到任何有效的结果,那么我们可以抛出最后得到的一个异常 ExecutionException ee = null ; long lastTime = timed ? System.nanoTime() : 0 ; Iterator<? extends Callable<T>> it = tasks.iterator(); // 首先先提交一个任务,后面的任务到下面的 for 循环一个个提交 futures.add(ecs.submit(it.next())); // 提交了一个任务,所以任务数量减 1 --ntasks; // 正在执行的任务数(提交的时候 +1,任务结束的时候 -1) int active = 1 ; for (;;) { // ecs 上面说了,其内部有一个 completionQueue 用于保存执行完成的结果 // BlockingQueue 的 poll 方法不阻塞,返回 null 代表队列为空 Future<T> f = ecs.poll(); // 为 null,说明刚刚提交的第一个线程还没有执行完成 // 在前面先提交一个任务,加上这里做一次检查,也是为了提高性能 if (f == null ) { if (ntasks > 0 ) { --ntasks; futures.add(ecs.submit(it.next())); ++active; } // 这里是 else if,不是 if。这里说明,没有任务了,同时 active 为 0 说明 // 任务都执行完成了。其实我也没理解为什么这里做一次 break? // 因为我认为 active 为 0 的情况,必然从下面的 f.get() 返回了 // 2018-02-23 感谢读者 newmicro 的 comment, // 这里的 active == 0,说明所有的任务都执行失败,那么这里是 for 循环出口 else if (active == 0 ) break ; // 这里也是 else if。这里说的是,没有任务了,但是设置了超时时间,这里检测是否超时 else if (timed) { // 带等待的 poll 方法 f = ecs.poll(nanos, TimeUnit.NANOSECONDS); // 如果已经超时,抛出 TimeoutException 异常,这整个方法就结束了 if (f == null ) throw new TimeoutException(); long now = System.nanoTime(); nanos -= now - lastTime; lastTime = now; } // 这里是 else。说明,没有任务需要提交,但是池中的任务没有完成,还没有超时(如果设置了超时) // take() 方法会阻塞,直到有元素返回,说明有任务结束了 else f = ecs.take(); } /* * 我感觉上面这一段并不是很好理解,这里简单说下。 * 1. 首先,这在一个 for 循环中,我们设想每一个任务都没那么快结束, * 那么,每一次都会进到第一个分支,进行提交任务,直到将所有的任务都提交了 * 2. 任务都提交完成后,如果设置了超时,那么 for 循环其实进入了“一直检测是否超时” 这件事情上 * 3. 如果没有设置超时机制,那么不必要检测超时,那就会阻塞在 ecs.take() 方法上, 等待获取第一个执行结果 * 4. 如果所有的任务都执行失败,也就是说 future 都返回了, 但是 f.get() 抛出异常,那么从 active == 0 分支出去(感谢 newmicro 提出) // 当然,这个需要看下面的 if 分支。 */ // 有任务结束了 if (f != null ) { --active; try { // 返回执行结果,如果有异常,都包装成 ExecutionException return f.get(); } catch (ExecutionException eex) { ee = eex; } catch (RuntimeException rex) { ee = new ExecutionException(rex); } } } // 注意看 for 循环的范围,一直到这里 if (ee == null ) ee = new ExecutionException(); throw ee; } finally { // 方法退出之前,取消其他的任务 for (Future<T> f : futures) f.cancel( true ); } } public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException { try { return doInvokeAny(tasks, false , 0 ); } catch (TimeoutException cannotHappen) { assert false ; return null ; } } public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return doInvokeAny(tasks, true , unit.toNanos(timeout)); } // 执行所有的任务,返回任务结果。 // 先不要看这个方法,我们先想想,其实我们自己提交任务到线程池,也是想要线程池执行所有的任务 // 只不过,我们是每次 submit 一个任务,这里以一个集合作为参数提交 public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException { if (tasks == null ) throw new NullPointerException(); List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size()); boolean done = false ; try { // 这个很简单 for (Callable<T> t : tasks) { // 包装成 FutureTask RunnableFuture<T> f = newTaskFor(t); futures.add(f); // 提交任务 execute(f); } for (Future<T> f : futures) { if (!f.isDone()) { try { // 这是一个阻塞方法,直到获取到值,或抛出了异常 // 这里有个小细节,其实 get 方法签名上是会抛出 InterruptedException 的 // 可是这里没有进行处理,而是抛给外层去了。此异常发生于还没执行完的任务被取消了 f.get(); } catch (CancellationException ignore) { } catch (ExecutionException ignore) { } } } done = true ; // 这个方法返回,不像其他的场景,返回 List<Future>,其实执行结果还没出来 // 这个方法返回是真正的返回,任务都结束了 return futures; } finally { // 为什么要这个?就是上面说的有异常的情况 if (!done) for (Future<T> f : futures) f.cancel( true ); } } // 带超时的 invokeAll,我们找不同吧 public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { if (tasks == null || unit == null ) throw new NullPointerException(); long nanos = unit.toNanos(timeout); List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size()); boolean done = false ; try { for (Callable<T> t : tasks) futures.add(newTaskFor(t)); long lastTime = System.nanoTime(); Iterator<Future<T>> it = futures.iterator(); // 每提交一个任务,检测一次是否超时 while (it.hasNext()) { execute((Runnable)(it.next())); long now = System.nanoTime(); nanos -= now - lastTime; lastTime = now; // 超时 if (nanos <= 0 ) return futures; } for (Future<T> f : futures) { if (!f.isDone()) { if (nanos <= 0 ) return futures; try { // 调用带超时的 get 方法,这里的参数 nanos 是剩余的时间, // 因为上面其实已经用掉了一些时间了 f.get(nanos, TimeUnit.NANOSECONDS); } catch (CancellationException ignore) { } catch (ExecutionException ignore) { } catch (TimeoutException toe) { return futures; } long now = System.nanoTime(); nanos -= now - lastTime; lastTime = now; } } done = true ; return futures; } finally { if (!done) for (Future<T> f : futures) f.cancel( true ); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | //高3位表示线程池状态, 后29位表示线程个数,记录线程池状态和线程数量 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0 )); ////线程数量统计位数29 Integer.SIZE=32 private static final int COUNT_BITS = Integer.SIZE - 3 ; //容量 000 11111111111111111111111111111 private static final int CAPACITY = ( 1 << COUNT_BITS) - 1 ; //运行状态 例:11100000000000000000000000000000 private static final int RUNNING = - 1 << COUNT_BITS; //关闭状态 例:00000000000000000000000000000000 private static final int SHUTDOWN = 0 << COUNT_BITS; //停止状态 例:00100000000000000000000000000000 private static final int STOP = 1 << COUNT_BITS; //整理状态 例:01000000000000000000000000000000 private static final int TIDYING = 2 << COUNT_BITS; //终止状态 例:01100000000000000000000000000000 private static final int TERMINATED = 3 << COUNT_BITS; //获取运行状态(获取前3位) private static int runStateOf( int c) { return c & ~CAPACITY; } //获取线程个数(获取后29位) private static int workerCountOf( int c) { return c & CAPACITY; } private static int ctlOf( int rs, int wc) { return rs | wc; RUNNING = 0 :接受新任务并且处理阻塞队列里的任务 SHUTDOWN = 1 :拒绝新任务但是处理阻塞队列里的任务 STOP = 2 :拒绝新任务并且抛弃阻塞队列里的任务同时会中断正在处理的任务 TIDYING :所有任务都执行完(包含阻塞队列里面任务)当前线程池活动线程为 0 ,将要调用terminated方法 TERMINATED = 3 :终止状态。terminated方法调用完成以后的状态 |
线程池状态转换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //任务队列 private final BlockingQueue<Runnable> workQueue; //工作者集合 private final HashSet<Worker> workers = new HashSet<Worker>(); //线程达到的最大值 private int largestPoolSize; //已完成任务总数 private long completedTaskCount; //线程工厂 private volatile ThreadFactory threadFactory; //拒绝策略 private volatile RejectedExecutionHandler handler; //闲置线程存活时间 private volatile long keepAliveTime; //是否允许核心线程超时 private volatile boolean allowCoreThreadTimeOut; //核心线程数量 private volatile int corePoolSize; //最大线程数量 private volatile int maximumPoolSize; //默认拒绝策略 private static final RejectedExecutionHandler defaultHandler = new AbortPolicy(); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //核心构造器 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 .corePoolSize = corePoolSize; //设置核心线程数量 this .maximumPoolSize = maximumPoolSize; //设置最大线程数量 this .workQueue = workQueue; //设置存放任务队列 this .keepAliveTime = unit.toNanos(keepAliveTime); //设置非核心线程存活时间 this .threadFactory = threadFactory; //设置用来生产线程的工厂 this .handler = handler; //设置不能再放入任务时候执行的拒绝策略 } |
ThreadPoolExecutor有多个构造器,所有的构造器都会调用上面的核心构造器。通过核心构造器我们可以为线程池设置不同的参数,由此线程池也能表现出不同的特性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public Future<?> submit(Runnable task) { if (task == null ) throw new NullPointerException(); RunnableFuture<Void> ftask = newTaskFor(task, null ); execute(ftask); return ftask; } public <T> Future<T> submit(Runnable task, T result) { if (task == null ) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task, result); execute(ftask); return ftask; } public <T> Future<T> submit(Callable<T> task) { if (task == null ) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; } |
submit 方法中,参数是 Runnable 类型(也有Callable 类型),这个参数不是用于new Thread(runnable).start()中的,也就是说此处的这个参数不是用于启动线程的,这里指的是任务,任务要做的事情是 run()方法里面定义的或 Callable 中的 call() 方法里面定义的。
-
调用submit方法,传入Runnable或者Callable对象
-
判断传入的对象是否为null,为null则抛出异常,不为null继续流程
-
将传入的对象转换为RunnableFuture对象
-
执行execute方法,传入RunnableFuture对象
-
返回RunnableFuture对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //核心执行方法 public void execute(Runnable command) { if (command == null ) throw new NullPointerException(); int c = ctl.get(); //线程数若小于corePoolSize则新建核心工作者 if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true )) return ; c = ctl.get(); } //否则将任务放到任务队列 if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); //若不是running状态则将该任务从队列中移除 if (!isRunning(recheck) && remove(command)) { //成功移除后再执行拒绝策略 reject(command); //若线程数为0则新增一个非核心线程 } else if (workerCountOf(recheck) == 0 ) { addWorker( null , false ); } //若队列已满则新增非核心工作者 } else if (!addWorker(command, false )) { //若新建非核心线程失败则执行拒绝策略 reject(command); } } |
-
调用execute方法,传入Runable对象
-
判断传入的对象是否为null,为null则抛出异常,不为null继续流程
-
获取当前线程池的状态和线程个数变量
-
判断当前线程数是否小于核心线程数,是走流程5,否则走流程6
-
添加线程数,添加成功则结束,失败则重新获取当前线程池的状态和线程个数变量,
-
判断线程池是否处于RUNNING状态,是则添加任务到阻塞队列,否则走流程10,添加任务成功则继续流程7
-
重新获取当前线程池的状态和线程个数变量
-
重新检查线程池状态,不是运行状态则移除之前添加的任务,有一个false走流程9,都为true则走流程11
-
检查线程池线程数量是否为0,否则结束流程,是调用addWorker(null, false),然后结束
-
调用!addWorker(command, false),为true走流程11,false则结束
-
调用拒绝策略reject(command),结束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | //工作者类 private final class Worker extends AbstractQueuedSynchronizer implements Runnable { //关联线程 final Thread thread; //初始任务 Runnable firstTask; //完成任务数 volatile long completedTasks; //构造器 Worker(Runnable firstTask) { //抑制中断直到runWorker setState(- 1 ); //设置初始任务 this .firstTask = firstTask; //设置关联线程 this .thread = getThreadFactory().newThread( this ); } public void run() { runWorker( this ); } //判断是否占有锁, 0代表未占用, 1代表已占用 protected boolean isHeldExclusively() { return getState() != 0 ; } //尝试获取锁 protected boolean tryAcquire( int unused) { if (compareAndSetState( 0 , 1 )) { setExclusiveOwnerThread(Thread.currentThread()); return true ; } return false ; } //尝试释放锁 protected boolean tryRelease( int unused) { 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) { //ignore } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | private boolean addWorker(Runnable firstTask, boolean core) { retry: for (;;) { int c = ctl.get(); int rs = runStateOf(c); //只有以下两种情况会继续添加线程 //1.状态为running //2.状态为shutdown,首要任务为空,但任务队列中还有任务 if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty())) { return false ; } for (;;) { int wc = workerCountOf(c); //以下三种情况不继续添加线程: //1.线程数大于线程池总容量 //2.当前线程为核心线程,且核心线程数达到corePoolSize //3.当前线程非核心线程,且总线程达到maximumPoolSize if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) { return false ; } //否则继续添加线程, 先将线程数加一 if (compareAndIncrementWorkerCount(c)) { //执行成功则跳过外循环 break retry; } //CAS操作失败再次检查线程池状态 c = ctl.get(); //如果线程池状态改变则继续执行外循环 if (runStateOf(c) != rs) { continue retry; } //否则表明CAS操作失败是workerCount改变, 继续执行内循环 } } boolean workerStarted = false ; boolean workerAdded = false ; Worker w = null ; try { final ReentrantLock mainLock = this .mainLock; w = new Worker(firstTask); final Thread t = w.thread; if (t != null ) { mainLock.lock(); try { int c = ctl.get(); int rs = runStateOf(c); if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null )) { //如果线程已经开启则抛出异常 if (t.isAlive()) throw new IllegalThreadStateException(); //将工作者添加到集合中 workers.add(w); int s = workers.size(); //记录线程达到的最大值 if (s > largestPoolSize) { largestPoolSize = s; } workerAdded = true ; } } finally { mainLock.unlock(); } //将工作者添加到集合后则启动线程 if (workerAdded) { t.start(); workerStarted = true ; } } } finally { //如果线程启动失败则回滚操作 if (!workerStarted) { addWorkerFailed(w); } } return workerStarted; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | //工作线程 final void runWorker(Worker w) { //获取当前工作线程 Thread wt = Thread.currentThread(); //获取工作者的初始任务 Runnable task = w.firstTask; //将工作者的初始任务置空 w.firstTask = null ; //将同步状态从-1设为0 w.unlock(); boolean completedAbruptly = true ; try { //初始任务不为空则执行初始任务, 否则从队列获取任务 while (task != null || (task = getTask()) != null ) { //确保获取到任务后才加锁 w.lock(); //若状态大于等于stop, 保证当前线程被中断 //若状态小于stop, 保证当前线程未被中断 //在清理中断状态时可能有其他线程在修改, 所以会再检查一次 if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) { wt.interrupt(); } try { //任务执行前做些事情 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(task, thrown); } } finally { //将执行完的任务置空 task = null ; //将完成的任务数加一 w.completedTasks++; w.unlock(); } } //设置该线程为正常完成任务 completedAbruptly = false ; } finally { //执行完所有任务后将线程删除 processWorkerExit(w, completedAbruptly); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | //从任务队列中获取任务 private Runnable getTask() { //上一次获取任务是否超时 boolean timedOut = false ; retry: //在for循环里自旋 for (;;) { int c = ctl.get(); int rs = runStateOf(c); //以下两种情况会将工作者数减为0并返回null,并直接使该线程终止: //1.状态为shutdown并且任务队列为空 //2.状态为stop, tidying或terminated if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { decrementWorkerCount(); return null ; } boolean timed; //判断是否要剔除当前线程 for (;;) { int wc = workerCountOf(c); //以下两种情况会在限定时间获取任务: //1.允许核心线程超时 //2.线程数大于corePoolSize timed = allowCoreThreadTimeOut || wc > corePoolSize; //以下两种情况不执行剔除操作: //1.上次任务获取未超时 //2.上次任务获取超时, 但没要求在限定时间获取 if (wc <= maximumPoolSize && !(timedOut && timed)) { break ; } //若上次任务获取超时, 且规定在限定时间获取, 则将线程数减一 if (compareAndDecrementWorkerCount(c)) { //CAS操作成功后直接返回null return null ; } //CAS操作失败后再次检查状态 c = ctl.get(); //若状态改变就从外层循环重试 if (runStateOf(c) != rs) { continue retry; } //否则表明是workerCount改变, 继续在内循环重试 } try { //若timed为true, 则在规定时间内返回 //若timed为false, 则阻塞直到获取成功 //注意:闲置线程会一直在这阻塞 Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); //获取任务不为空则返回该任务 if (r != null ) { return r; } //否则将超时标志设为true timedOut = true ; } catch (InterruptedException retry) { timedOut = false ; } } } |
工作线程在while循环里不断的通过getTask方法来从任务队列中获取任务,我们看一下getTask方法是怎样获取任务的。进入第一个for循环之后有一个if判断,从这里我们可以看到,如果线程池状态为shutdown,会继续消费任务队列里面的任务;如果线程池状态为stop,则停止消费任务队列里剩余的任务。进入第二个for循环后会给timed变量赋值,由于allowCoreThreadTimeOut变量默认是false,所以timed的值取决于线程数是否大于corePoolSize,小于为false,大于则为true。从任务队列里面获取任务的操作在try块里面,如果timed为true,则调用poll方法进行定时获取;如果timed为flase,则调用take方法进行阻塞获取。也就是说默认情况下,如果线程数小于corePoolSize,则调用take方法进行阻塞获取,即使任务队列为空,工作线程也会一直等待;如果线程数大于corePoolSize,则调用poll方法进行定时获取,在keepAliveTime时间内获取不到任务则会返回null,对应的工作线程也会被移除,但线程数会保持在corePoolSize上。当然如果设置allowCoreThreadTimeOut为true,则会一直通过调用poll方法来从任务队列中获取任务,如果任务队列长时间为空,则工作线程会减少至0。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | //删除工作线程 private void processWorkerExit(Worker w, boolean completedAbruptly) { //若非正常完成则将线程数减为0 if (completedAbruptly) { decrementWorkerCount(); } final ReentrantLock mainLock = this .mainLock; mainLock.lock(); try { //统计完成的任务总数 completedTaskCount += w.completedTasks; //在这将工作线程移除 workers.remove(w); } finally { mainLock.unlock(); } //尝试终止线程池 tryTerminate(); //再次检查线程池状态 int c = ctl.get(); //若状态为running或shutdown, 则将线程数恢复到最小值 if (runStateLessThan(c, STOP)) { //线程正常完成任务被移除 if (!completedAbruptly) { //允许核心线程超时最小值为0, 否则最小值为核心线程数 int min = allowCoreThreadTimeOut ? 0 : corePoolSize; //如果任务队列还有任务, 则保证至少有一个线程 if (min == 0 && !workQueue.isEmpty()) { min = 1 ; } //若线程数大于最小值则不新增了 if (workerCountOf(c) >= min) { return ; } } //新增工作线程 addWorker( null , false ); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | //平缓关闭线程池 public void shutdown() { final ReentrantLock mainLock = this .mainLock; mainLock.lock(); try { //检查是否有关闭的权限 checkShutdownAccess(); //将线程池状态设为shutdown advanceRunState(SHUTDOWN); //中断闲置的线程 interruptIdleWorkers(); //对外提供的钩子 onShutdown(); } finally { mainLock.unlock(); } //尝试终止线程池 tryTerminate(); } //立刻关闭线程池 public List<Runnable> shutdownNow() { List<Runnable> tasks; final ReentrantLock mainLock = this .mainLock; mainLock.lock(); try { //检查是否有关闭的权限 checkShutdownAccess(); //将线程池状态设为stop advanceRunState(STOP); //中断所有工作线程 interruptWorkers(); //排干任务队列 tasks = drainQueue(); } finally { mainLock.unlock(); } //尝试终止线程池 tryTerminate(); return tasks; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | final void tryTerminate() { for (;;) { int c = ctl.get(); //以下两种情况终止线程池,其他情况直接返回: //1.状态为stop //2.状态为shutdown且任务队列为空 if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && !workQueue.isEmpty())) { return ; } //若线程不为空则中断一个闲置线程后直接返回 if (workerCountOf(c) != 0 ) { interruptIdleWorkers(ONLY_ONE); return ; } final ReentrantLock mainLock = this .mainLock; mainLock.lock(); try { //将状态设置为tidying if (ctl.compareAndSet(c, ctlOf(TIDYING, 0 ))) { try { //线程池终止后做的事情 terminated(); } finally { //将状态设置为终止状态(TERMINATED) ctl.set(ctlOf(TERMINATED, 0 )); //唤醒条件队列所有线程 termination.signalAll(); } return ; } } finally { mainLock.unlock(); } //若状态更改失败则再重试 } } |
1 2 3 4 5 6 7 8 9 | public interface ThreadFactory { Thread newThread(Runnable r); } Executors.defaultThreadFactory()实现 public static ThreadFactory defaultThreadFactory() { return new DefaultThreadFactory(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger( 1 ); //原子类,线程池编号 private final ThreadGroup group; //线程组 private final AtomicInteger threadNumber = new AtomicInteger( 1 ); //线程数目 private final String namePrefix; //为每个创建的线程添加的前缀 DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null ) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); //取得线程组 namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-" ; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0 ); //真正创建线程的地方,设置了线程的线程组及线程名 if (t.isDaemon()) t.setDaemon( false ); if (t.getPriority() != Thread.NORM_PRIORITY) //默认是正常优先级 t.setPriority(Thread.NORM_PRIORITY); return t; } } |
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术