多线程-ThreadPoolExecutor
线程池
线程池是可以控制线程创建、释放、并通过某种策略尝试复用线程去执行任务的一种管理框架,从而实现线程资源与任务之间的一种平衡。
类图
Executor
public interface Executor {
void execute(Runnable command);
}
ExecutorService
public interface ExecutorService extends Executor {
/**
* 启动一次有序的关闭,之前提交的任务执行,但不接受新任务
*/
void shutdown();
/**
* 试图停止所有正在执行的任务,暂停处理正在等待的任务,返回一个等待执行的任务列表
* 这个方法不会等待正在执行的任务终止
*/
List<Runnable> shutdownNow();
// 如果已经被shutdown,返回true
boolean isShutdown();
// 如果所有任务都已经被终止,返回true
boolean isTerminated();
// 在一个shutdown请求后,阻塞的等待所有任务执行完毕
// 或者到达超时时间,或者当前线程被中断
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
// 提交一个有返回值的任务,并返回一个Future代表等待的任务执行的结果, 等到任务成功执行,Future#get()方法会返回任务执行的结果
<T> Future<T> submit(Callable<T> task);
// 提交一个可以执行的任务,返回一个Future代表这个任务, 等到任务执行结束,Future#get()方法会返回这个给定的result
<T> Future<T> submit(Runnable task, T result);
// 提交一个可执行的任务,返回一个Future代表这个任务, 等到任务成功执行,Future#get()方法会返回null
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;
AbstractExecutorService
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;
}
模板方法模式是一种基于继承的代码复用技术,它是一种类行为型模式。
模板方法模式是结构最简单的行为型设计模式,在其结构中只存在父类与子类之间的继承关系。通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。模板方法模式提供了一个模板方法来定义算法框架,而某些具体步骤的实现可以在其子类中完成。
TheadPoolExecutor
public class ThreadPoolExecutor extends AbstractExecutorService {
}
ScheduledExecutorService
public interface ScheduledExecutorService extends ExecutorService {
/**
* 在给定延时后,创建并执行一个一次性的Runnable任务,任务执行完毕后,ScheduledFuture#get()方法会返回null
*/
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);
/**
* 在给定延时后,创建并执行一个ScheduledFutureTask,ScheduledFuture 可以获取结果或取消任务
*/
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);
/**
* 创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期,也就是将在 initialDelay 后开始执行,然后在 initialDelay+period 后执 行,接着在 initialDelay + 2 * period 后执行,依此类推
* 如果执行任务发生异常,随后的任务将被禁止,否则任务只会在被取消或者Executor被终止后停止,如果任何执行的任务超过了周期,随后的执行会延时,不会并发执行
*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
/**
* 创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟
* 如果执行任务发生异常,随后的任务将被禁止,否则任务只会在被取消或者Executor被终止后停止
*/
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);
}
ScheduledThreadPoolExecutor
public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService {
}
Executors
public static ExecutorService newCachedThreadPool();
public static ExecutorService newFixedThreadPool(int nThreads);
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize);
public static ExecutorService newSingleThreadExecutor();
(1)newCachedThreadPool: 创建一个可缓存工作线程的线程池,默认存活时间是60s,线程数量可达到Integer.MAX_VALUE,内部使用SynchronousQueue作为阻塞队列;
ThreadPoolExecutor
ThreadPoolExecutor及其交互类
RejectedExecutionHandler(拒绝策略或饱和策略)
ThreadFactory
public interface ThreadFactory {
Thread newThread(Runnable r);
}
很显然这个工厂模式(或工厂方法模式)的应用。工厂方法模式:定义一个用于创建对象的接口(如ThreadFactory),然子类决定将哪一个类实例化(比如Executors.DefaultThreadFactory),让一个类的实例化延迟到其子类。
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;
}
}
构造函数
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,
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) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
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)如果线程池中线程数量小于corePoolSize,就创建新的线程来执行新添加的任务;
线程池状态
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS; // Packing and unpacking ctl
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
execute方法
public void execute(Runnable command) {
if (command == null) // 不允许提交空任务
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) { // 如果wc < corePoolSize则直接创建新任务执行
if (addWorker(command, true)) // 如果提交成功则直接退出,失败的原因有:(1)线程池已经shutdown(2)wc < corePoolSize之后,由于并发导致wc>=corePoolSize
return;
c = ctl.get();// 凡是需要再次使用ctl做判断时,都会再次调用ctl.get()获取最新值
}
if (isRunning(c) && workQueue.offer(command)) { // 如果corePoolSize < wc < maximumPoolSize && 运行中,则入队列;如果队列满,则可能入队失败
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command)) // 如果线程池不是running状态,应该拒绝添加新任务,出队列;双重检测,回滚入队列;删除队列元素失败的场景可能是:刚好有一个线程执行了该任务。
reject(command);
else if (workerCountOf(recheck) == 0) // 如果线程池中无活动的线程,则增加一个线程,可能不断从队列中获取任务并执行。
addWorker(null, false); // 添加一个线程
}
else if (!addWorker(command, false)) // 如果队列满了,则创建新线程运行任务,
reject(command); // 如果失败,则说明线程池shutdown或者饱和了
}
具体流程图如下:
addWorker
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) { // 外层循环,负责判断线程池状态
int c = ctl.get();
int rs = runStateOf(c);
<span style="white-space:pre"> </span> // 线程池状态值的大小为:RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED
// 有如下几种场景是可以直接拒绝增加新线程的:rs至少是SHUTDOWN状态,以下3个条件任意一个是false(1)rs==SHUTDOWN,false的情况是:线程池已经超过了SHUTDOWn状态,可能是STOP,TIDYING,TERMINATED其中之一,即线程已经终止了(2)firstTask==null,隐含rs==SHUTDOWN,false:firstTask!=null,场景是线程池已经shutdown,还要添加新的任务,拒绝(3)!workQueue.isEmpty(),隐含rs==SHUTDOWN && firstTask==null,false:wq为空,当firstTask为空是为了创建一个没有任务的线程,从wq中获取任务,如果wq为空,就没有添加新线程的必要了。
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false; for (;;) { // 内层循环,负责workerCount + 1
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize)) // 如果wc > 线程池最大上限CAPACITY,或者wc > corePoolSize(maximumPoolSize)
return false;
if (compareAndIncrementWorkerCount(c)) // CAS操作,使得wc + 1,成功则跳出retry循环,标示累加成功
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs) // 如果之前的CAS操作失败,需要从新获取线程池状态,如果与之前不一致,跳出内循环,继续去外层循环判断
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
} 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)) { // 如果线程池在运行,或者线程池已经shutdown且firstTask==null(可能是wq中有未执行完成的任务,攒国家没有初始化的worker去执行队列中的任务)
if (t.isAlive()) // precheck that t is startable
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;
}
其实在execute里面已经使用了前3种:
内部类Worker
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable {
/** Thread this worker is running in. Null if factory fails. */
final Thread thread;
/** Initial task to run. Possibly null. */
Runnable firstTask;
/** Per-thread task counter */
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
public void run() {
runWorker(this);
}
}
1、初始AQS状态为-1,此时不允许中断interrupt(),只有在worker线程启动了,执行了runWoker(),将state置为0,才能中断
不允许中断体现在:
A、shutdown()线程池时,会对每个worker tryLock()上锁,而Worker类这个AQS的tryAcquire()方法是固定将state从0->1,故初始状态state==-1时tryLock()失败,没发interrupt()
B、shutdownNow()线程池时,不用tryLock()上锁,但调用worker.interruptIfStarted()终止worker,interruptIfStarted()也有state>0才能interrupt的逻辑
2、为了防止某种情况下,在运行中的worker被中断,runWorker()每次运行任务时都会lock()上锁,而shutdown()这类可能会终止worker的操作需要先获取worker的锁,这样就防止了中断正在运行的线程
Worker实现的AQS为不可重入锁,为了是在获得worker锁的情况下再进入其它一些需要加锁的方法
runWorker(Worker)
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // 此处将state状态设置为0,允许中断
boolean completedAbruptly = true; // true:异常退出,false:正常退出
try {
while (task != null || (task = getTask()) != null) { // 如果firstTask == null,则从队列中获取。
w.lock();// 不是为了防止并发,而是为了在shutdown状态下,不能终止正在运行的worker(worker是不可重入锁)
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++; // 完成任务 + 1
w.unlock(); // 解锁
}
}
completedAbruptly = false;// 正常执行
} finally {
processWorkerExit(w, completedAbruptly); // 处理worker退出
}
}
getTask()
private Runnable getTask() {
boolean timedOut = false; // 调用最新的poll()是否超时? for (;;) {
int c = ctl.get();
int rs = runStateOf(c); // Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { // (1)如果线程池状态为>=stop(2)线程池状态为SHUTDOWN并且队列为空
decrementWorkerCount();
return null;
} int wc = workerCountOf(c); // Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; // 默认allowCoreThreadTimeOut=false,所以当workerCount > corePoolSize时
// 这个分支包括4种情况:(1)wc > maximumPoolSize && wc > 1 (2) wc > maximumPoolSize && workQueue.isEmpty()
// (3)timed && timedOut && wc > 1 (4) timed && timedOut && workQueue.isEmpty()
if ((wc > maximumPoolSize || (timed && timedOut)) // wc >
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 如果workerCount > corePoolSize,则超时获取任务,否则阻塞获取任务
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); if (r != null) // 如果r == null肯定是超时获取的任务
return r; timedOut = true; // 只要超时获取那一直都是这个状态
} catch (InterruptedException retry) {
timedOut = false; // 如果在阻塞过程中,被interrrupt,重置timedOut为false
}
}
}
1、首先判断是否可以满足从workQueue中获取任务的条件,不满足return null
A、线程池状态是否满足:
(a)shutdown状态 + workQueue为空 或 stop状态,都不满足,因为被shutdown后还是要执行workQueue剩余的任务,但workQueue也为空,就可以退出了
(b)stop状态,shutdownNow()操作会使线程池进入stop,此时不接受新任务,中断正在执行的任务,workQueue中的任务也不执行了,故return null返回
B、线程数量是否超过maximumPoolSize 或 获取任务是否超时
(a)线程数量超过maximumPoolSize可能是线程池在运行时被调用了setMaximumPoolSize()被改变了大小,否则已经addWorker()成功不会超过maximumPoolSize
(b)如果 当前线程数量>corePoolSize,才会检查是否获取任务超时,这也体现了当线程数量达到maximumPoolSize后,如果一直没有新任务,会逐渐终止worker线程直到corePoolSize
2、如果满足获取任务条件,根据是否需要定时获取调用不同方法:
A、workQueue.poll():如果在keepAliveTime时间内,阻塞队列还是没有任务,返回null
B、workQueue.take():如果阻塞队列为空,当前线程会被挂起等待;当队列中有任务加入时,线程被唤醒,take方法返回任务
3、在阻塞从workQueue中获取任务时,可以被interrupt()中断,代码中捕获了InterruptedException,重置timedOut为初始值false,再次执行第1步中的判断,满足就继续获取任务,不满足return null,会进入worker退出的流程
processWorkerExit(Worker w, boolean completedAbruptly)线程退出
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // 如果true说明worker是异常退出,如果是false标示worker是正常退出并且worker没有可执行的task,不用-1,因为在getTask里面已经-1
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)) { // 如果状态是running和shutdown
if (!completedAbruptly) { // 如果线程是异常退出,则直接addWorker,
int min = allowCoreThreadTimeOut ? 0 : corePoolSize; // allowCoreThreadTimeOut默认是false,即min默认为corePoolSize
if (min == 0 && ! workQueue.isEmpty()) // allowCoreThreadTimeOut=false标示核心线程即使空闲也要保持存活,如果=true,则标示使用keepAliveTime标示存活时间
min = 1; // 如果队列不空,那么至少也要保持一个线程存在
if (workerCountOf(c) >= min) // 如果线程池中线程数量>=min,则直接返回,否则需要addWorker
return; // replacement not needed
}
addWorker(null, false);
}
}
参数:
worker: 要结束的worker
completedAbruptly: 是否突然完成(是否因为异常退出)
执行流程:
1、worker数量-1
A、如果是突然终止,说明是task执行时异常情况导致,即run()方法执行时发生了异常,那么正在工作的worker线程数量需要-1
B、如果不是突然终止,说明是worker线程没有task可执行了,不用-1,因为已经在getTask()方法中-1了
2、从Workers Set中移除worker,删除时需要上锁mainlock
3、tryTerminate():在对线程池有负效益的操作时,都需要“尝试终止”线程池,大概逻辑:
判断线程池是否满足终止的状态
A、如果状态满足,但还有线程池还有线程,尝试对其发出中断响应,使其能进入退出流程
B、没有线程了,更新状态为tidying->terminated
4、是否需要增加worker线程,如果线程池还没有完全终止,仍需要保持一定数量的线程
线程池状态是running 或 shutdown
A、如果当前线程是突然终止的,addWorker()
B、如果当前线程不是突然终止的,但当前线程数量 < 要维护的线程数量,addWorker()
故如果调用线程池shutdown(),直到workQueue为空前,线程池都会维持corePoolSize个线程,然后再逐渐销毁这corePoolSize个线程
终止线程池
shutdown()平滑终止线程池
// 终止线程池,之前提交的任务会执行完,但是新提交的任务会拒绝,重复调用无影响,该方法不会等待线程池真正的终止。
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);// 设置线程状态,该方法只允许设置stop和shutdown,tidying和terminated状态在tryTerminate()方法中设置,内部是利用CAS+循环设置线程状态
interruptIdleWorkers(); // 中断所有的空闲worker
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate(); // 尝试终止线程池
}
interruptIdleWorkers()中断空闲worker
/ onlyOne如果为true,最多interrupt一个worker;空闲线程:等待任务的线程,即中断在等待任务的线程(没有上锁),中断唤醒继续循环,会判断线程池状态退出获取task
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) { // 运行中的worker,是占用锁的,而worker是非重入锁,即运行中的worker不能中断。
try {
t.interrupt();
} catch (SecurityException ignore) { } finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
tryTerminate()尝试终止线程池
// 以下场景线程池变为terminated,(1)shutdown && wc == 0 && wq.isEmpty()(2)stop状态
// 这个方法必须在任何可能导致线程池终止的情况下被调用,如减少worker数量等。
final void tryTerminate() {
for (;;) {
int c = ctl.get();
if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) // 3种情况不需要中断线程池(1)running(2)状态是tidying或terminated(3)SHUTDOWN并且队列不空
return;
if (workerCountOf(c) != 0) { // 只有SHUTDOWN并且队列空或者stop状态能到这里
interruptIdleWorkers(ONLY_ONE); // 中断一个正在等待任务的空闲worker
return;
}
// 如果SHUTDOWN队列空,运行的worker也没有了,则可以terminated了
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { // tidying状态
try {
terminated();
} finally {
ctl.set(ctlOf(TERMINATED, 0));// terminated状态
termination.signalAll();//真正的终止了线程池,唤醒因为调用了awaitTermination()方法而阻塞的线程。
}
return;
}
} finally {
mainLock.unlock();
} // else retry on failed CAS
}
}
shutdownNow()不友好的终止线程池
// 粗鲁的终止线程池,并返回等待执行的任务列表
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers(); // 中断所有线程,包括运行的。
tasks = drainQueue(); // 返回等待处理的任务
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
interrruptWorkers()中断所有worker
// 中断所有worker
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
} void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { // state是否大于零,即worker是否已经开始运行并且还未interrupt
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
awaitTermination()等待线程池终止
// 等待线程池终止
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (;;) {
if (runStateAtLeast(ctl.get(), TERMINATED))
return true; // 终止返回true
if (nanos <= 0) // 超时返回false
return false;
nanos = termination.awaitNanos(nanos);
}
} finally {
mainLock.unlock();
}
}
exec.shutdown();
try{
while(!exec.awaitTermination(500, TimeUnit.MILLISECONDS)) {
LOGGER.debug("Waiting for terminate");
}
} catch (InterruptedException e) {
//中断处理
}
多线程-ThreadPoolExecutor的更多相关文章
- java多线程 ThreadPoolExecutor 策略的坑
无论是使用jdk的线程池ThreadPoolExecutor 还是spring的线程池ThreadPoolTaskExecutor 都会使用到一个阻塞队列来进行存储线程任务. 当线程不够用时,则将后续 ...
- Java 多线程读取文件并统计词频 实例 出神入化的《ThreadPoolExecutor》
重在展示多线程ThreadPoolExecutor的使用,和线程同步器CountDownLatch,以及相关CAS的原子操作和线程安全的Map/队列. ThreadPool主线程 1 import j ...
- python中同步、多线程、异步IO、多线程对IO密集型的影响
目录 1.常见并发类型 2.同步版本 3.多线程 4.异步IO 5.多进程 6.总结 1.常见并发类型 I/ O密集型: 蓝色框表示程序执行工作的时间,红色框表示等待I/O操作完成的时间.此图没有按比 ...
- python concurrent.futures
python因为其全局解释器锁GIL而无法通过线程实现真正的平行计算.这个论断我们不展开,但是有个概念我们要说明,IO密集型 vs. 计算密集型. IO密集型:读取文件,读取网络套接字频繁. 计算密集 ...
- 多线程学习笔记-深入理解ThreadPoolExecutor
java多线程中,线程池的最上层接口是Executor,ExecutorService实现了Executor,是真正的管理线程池的接口,ThreadPoolExecutor间接继承了ExecutorS ...
- 使用ThreadPoolExecutor进行多线程编程
ThreadPoolExecutor有四个构造函数,分别是: 1,ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keep ...
- 多线程相关-ThreadPoolExecutor
应用层面: ThreadPoolExecutor: 创建多线程池执行器:new ThreadPoolExecutor(),创建方法最终都是走的以下这个构造方法: /** * Creates a new ...
- Java多线程系列——线程池原理之 ThreadPoolExecutor
ThreadPoolExecutor 简介 ThreadPoolExecutor 是线程池类. 通俗的讲,它是一个存放一定数量线程的线程集合.线程池允许多个线程同时运行,同时运行的线程数量就是这个线程 ...
- java多线程系列:ThreadPoolExecutor源码分析
前言 这篇主要讲述ThreadPoolExecutor的源码分析,贯穿类的创建.任务的添加到线程池的关闭整个流程,让你知其然所以然.希望你可以通过本篇博文知道ThreadPoolExecutor是怎么 ...
随机推荐
- Oracle SQL执行缓慢的原因以及解决方案
以下的文章抓哟是对Oracle SQL执行缓慢的原因的分析,如果Oracle数据库中的某张表的相关数据已是2亿多时,同时此表也创建了相关的4个独立的相关索引.由于业务方面的需要,每天需分两次向此表中 ...
- 给ul下的li加click时间
$('.province ul li').click(function() {//方法 });
- python对于0x01的处理
对于python脚本,可以使用: .replace('\x01', '') 对于vim工具,可以使用: :%s/\%x01/ /g
- 深度增强学习--DPPO
PPO DPPO介绍 PPO实现 代码DPPO
- C#-遍历datatable的几种方法
遍历datatable的方法2009-- :02方法一: DataTable dt = dataSet.Tables[]; ; i < dt.Rows.Count ; i++) { string ...
- [Tools] Batch Create Markdown Files from a Template with Node.js and Mustache
Creating Markdown files from a template is a straightforward process with Node.js and Mustache. You ...
- next 前缀字符串
我们在一个母字符串中查找一个子字符串有很多方法.KMP是一种最常见的改进算法,它可以在匹配过程中失配的情况下,有效地多往后面跳几个字符,加快匹配速度. 当然我们可以看到这个算法针对的是子串有对称属性, ...
- AutoCAD .NET二次开发(二)
今天专门讲一个--CommandMethod.我们都在知道CAD操作要快,必须要熟悉掌握各种命令.在Lisp开发中,在函数后C:即可添加一个命令,非常方法,在.NET API也可以非常方便的设置命令, ...
- Gstreamer学习
Gstreamer学习笔记----Gstreamer架构设计思想 http://blog.csdn.net/tx3344/article/details/7497434 Gstreamer到底是个啥? ...
- Python Hashtable的理解
一个对象当其生命周期内的hash值不发生改变,而且可以跟其他对象进行比较时,这个对象就是Hashtable的.两者Hashtable的对象只有具有相同的hash值时才能判断为相同的对象. ...