概述 任务是一组逻辑工作单元,而线程则是是任务异步执行的机制。通过线程池就可以简化线程的管理工作。 ThreadPoolExecutor是线程池的核心实现。线程池中预先提供了指定数量的可重用的线程,使用线程池避免了线程创建和终止的开销,节省了系统的资源。并且线程池维护了一些基础的数据统计,方便了线程的监控和管理。
线程池的基本使用 参数解释 线程池的创建的需要指定非常多的参数,我们需要理解每个参数的含义.我们就以参数最多的构造器为例,来解释每个参数的含义。
1 2 3 4 5 6 7 ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize 核心线程数。maximumPoolSize最大线程数。 这里需要注意:当一个新的任务提交给线程池之后:
如果当前运行线程的数量小于核心线程数,无论有无空闲的线程,都换创建新的线程。
如果当前运行的线程数大于核心线程数,小于最大线程数,只有当等待队列满之后,才会新建线程。
如果等待队列已满,且线程数已达到最大线程数,那么就会根据指定的拒绝策略进行处理了。
keepAliveTime线程最大空闲时间:如果当前线程池中多于核心线程数的线程如果超过最大空闲时间就会被终止。
unit:TimeUnit时间单位。workQueue线程等待队列。threadFactory线程创建工厂。RejectedExecutionHandler:拒绝策略。当线程池已经关闭或者已经达到饱和状态,新提交的任务会被拒绝。一共有4种拒绝策略:
AbortPolicy:默认策略,在需要拒绝任务时,抛出RejectedExecutionException
CallerRunsPolicy:直接在execute方法的调用线程种运行被拒绝的任务,如果线程池已经关闭,任务将被丢弃。
DiscardPolicy:直接丢弃任务
DiscardOldestPolicy:丢弃队列中等待时间最长的任务,并执行当前提交的任务,如果线程池被关闭,任务将被丢弃。
我们也可以自己继承RejectedExcutionHandler自定义自己的拒绝策略,拒绝策略的运行需要指定线程池和队列的容量。
生命周期 线程池一共有5种状态:
Running:可以接收新的任务和队列任务
shutdown:不接受新的任务,但是会运行队列任务。
stop:不接受新的任务,也不会运行队列任务,并且中断正在运行的任务。
tidying:所有任务都已经终止,workCount为0,当前池状态为tidying时会运行运行terminated()方法
terminated,terminated()方法执行完毕。
源码分析
重要属性 ThreadPoolExecutor内部有一个非常重要的内部类Worker,它继承自AQS实现了Runnable接口,实现了不可重入的互斥锁。在线程池种持有一个Work集合,一个worker对应一个工作想,当线程池启动时,对应的worker会执行池种的任务,执行任务完毕后会从阻塞列表中获取一个新的任务继续执行。
Worker内部维护了三个变量,用于记录每个工作线程的工作状态。
1 2 3 4 5 6 7 final Thread thread;Runnable firstTask; volatile long completedTasks;
内部的属性:
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 private final BlockingQueue<Runnable> workQueue;private final ReentrantLock mainLock = new ReentrantLock ();private final HashSet <Worker> workers = new HashSet <Worker>();private final Condition termination = mainLock.newCondition();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 (); private static final RuntimePermission shutdownPerm = new RuntimePermission ("modifyThread" ); private final AtomicInteger ctl = new AtomicInteger (ctlOf(RUNNING, 0 ));
重要方法解析 execute方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public void execute (Runnable command) { if (command == null ) throw new NullPointerException (); int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true )) return ; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0 ) addWorker(null , false ); } else if (!addWorker(command, false )) reject(command); }
提交一个任务到线程池,任务不一定会立即执行。提交的任务可以在一个新的线程中执行,也可能在已存在线程中执行。如果由于池关闭或池容量已经饱和导致任务无法提交,那么就根据拒绝策略来处理提交过来的任务。
如果正在运行的线程数少于corePoolSize,那么就会通过addWorker方法尝试开启一个新的线程并把提交的任务作为它的firstTask运行,addWorker会检查ctl的状态来判断是否可以添加新的线程。
如果addWorker执行失败(返回false),那么就会把任务添加到等待队列。这里需要对ctl进行双重检查。
如果不能任务不能入队,那么就会再次尝试增加一个新的线程,如果添加失败,就意味着池关闭或已经饱和,这个时候就会根据拒绝策略来进行处理。
addWorker方法 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 private boolean addWorker (Runnable firstTask, boolean core) { retry: for (;;) { int c = ctl.get(); int rs = runStateOf(c); if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())) return false ; for (;;) { int wc = workerCountOf(c); if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) return false ; 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 { int rs = runStateOf(ctl.get()); 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; }
runWorker方法 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 final void runWorker (Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null ; w.unlock(); boolean completedAbruptly = true ; try { while (task != null || (task = getTask()) != null ) { w.lock(); 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); } }
runWorker是工作线程运行的核心方法,循环从队列中获取任务并执行。工作线程启动后,会首先运行内部持有的任务firstTask.如果firstTask为null,那么就会循环调用getTask方法从队列中获取任务执行。在任务执行前后可以调用beforeExecute和afterWxecute处理执行前后的逻辑。如果线程池的状态正在停止,那么需要确保线程被中断,否则需要确保线程没有被中断。
getTask方法 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 private Runnable getTask () { boolean timedOut = false ; for (;;) { int c = ctl.get(); int rs = runStateOf(c); if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { decrementWorkerCount(); return null ; } int wc = workerCountOf(c); boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) { if (compareAndDecrementWorkerCount(c)) return null ; continue ; } try { Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); if (r != null ) return r; timedOut = true ; } catch (InterruptedException retry) { timedOut = false ; } } }
processWorkerExit方法 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 private void processWorkerExit (Worker w, boolean completedAbruptly) { 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(); if (runStateLessThan(c, STOP)) { if (!completedAbruptly) { int min = allowCoreThreadTimeOut ? 0 : corePoolSize; if (min == 0 && ! workQueue.isEmpty()) min = 1 ; if (workerCountOf(c) >= min) return ; } addWorker(null , false ); } }
工作线程处理完所有的任务之后,调用池方法处理工作线程退出逻辑,为已经死亡的工作线程执行相关的清除操作。此方法会从线程池中内的工作线程集合中移除当前线程,并会尝试终止线程池。 在下面这几种情况下,可能会替换当前工作线程:
用户任务执行异常导致线程退出
工作线程数少于corePoolSize
等待队列不为空,但是没有工作线程
tryTerminate方法 该方法的主要作用就是尝试终止线程池。
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 final void tryTerminate () { for (;;) { int c = ctl.get(); 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 { if (ctl.compareAndSet(c, ctlOf(TIDYING, 0 ))) { try { terminated(); } finally { ctl.set(ctlOf(TERMINATED, 0 )); termination.signalAll(); } return ; } } finally { mainLock.unlock(); } } }
该方法用于尝试终止线程池,shutDown,shutdownNoe,remove中局势通过此方法来终止线程池的。此方法必须在人恶化可能导致终止的行为之后被调用。一如减少工作线程数,移除队列中的任务,或者是在工作线程运行完毕后处理工作线程退出逻辑方法processWorkerExit。