前言
多线程是我们日常工作中很少能接触到的技术,但是面试
的时候100%
会被问到,万一工作中用到了基本不会,本篇咱们就来深入分析线程池的实现类ThreadPoolExecutor
。
1、构造方法
构造方法中有4个方法,本质上都是调用的下面这个构造方法:
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;
}
复制代码
2、饱和策略
上面的构造方法中,我们着重需要注意的是饱和策略,线程池中定义了四种饱和策略:
1、CallerRunsPolicy
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
//使用主线程执行新任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
//此方法相同于同步方法
r.run();
}
}
}
复制代码
2、 AbortPolicy(线程池默认的策略)
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//抛出 RejectedExecutionException来拒绝新任务的处理
throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());
}
}
复制代码
3、DiscardPolicy
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
//不执行任何操作,丢弃新任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
复制代码
4、DiscardOldestPolicy
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
//此策略将丢弃最早的未处理的任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
复制代码
3、阻塞队列
咱们看下ThreadPoolExecutor的源码:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
复制代码
使用的是LinkedBlockingQueue
作为阻塞队列,LinkedBlockingQueue的默认构造函数允许的队列长度是Integer.MAX_VALUE,若堆积大量的请求,可能会造成OOM。
此处就是为什么《阿里巴巴 Java 开发手册》
中不推荐使用Executors工具类创建线程池的原因,要求使用 ThreadPoolExecutor
构造函数的方式,让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
4、execute方法
下面是执行流程图:
//core为true,"最大线程数"就是核心线程数,则表明创建核心线程数失败if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 成功通过CAS更新工作线程数wc,则break到最外层的循环
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
// 如果线程的状态改变了就跳到外层循环执行
if (runStateOf(c) != rs)
continue retry;
//如果CAS更新工作线程数wc失败,则可能是并发更新导致的失败,继续在内层循环重试即可
// 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)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
//把创建的工作线程实例添加到工作线程集合
workers.add(w);
/更新当前工作线程的峰值容量largestPoolSize
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;
}
复制代码
5、shutdown方法
线程池不用了,要关闭线程池,下面是源码:
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
// 获取锁
mainLock.lock();
try {
//校验是否有权限。
checkShutdownAccess();
//设置SHUTDOWN状态。
advanceRunState(SHUTDOWN);
//中断线程池中所有空闲线程。
interruptIdleWorkers();
//钩子函数
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
//释放锁
mainLock.unlock();
}
//尝试终止线程池
tryTerminate();
}
复制代码
结束语
本篇详细的分析了ThreadPoolExecutor的execute方法,耗费了不少时间。如果本文对你哪怕是有一点点的帮助,就值了。
原文转载:http://www.shaoqun.com/a/504715.html
打折网站:https://www.ikjzd.com/w/74
trax:https://www.ikjzd.com/w/1489
前言多线程是我们日常工作中很少能接触到的技术,但是面试的时候100%会被问到,万一工作中用到了基本不会,本篇咱们就来深入分析线程池的实现类ThreadPoolExecutor。1、构造方法构造方法中有4个方法,本质上都是调用的下面这个构造方法:publicThreadPoolExecutor(intcorePoolSize,intmaximumPoolSize,longkeepAliveTime,
败欧洲网站:败欧洲网站
好东东网:好东东网
惠州大甲岛好玩吗?:惠州大甲岛好玩吗?
2019年亚马逊将的运营方向有这六大举措!:2019年亚马逊将的运营方向有这六大举措!
干不过阿里!亚马逊在华破局无望!在美转型艰难,关停全美快闪店:干不过阿里!亚马逊在华破局无望!在美转型艰难,关停全美快闪店
No comments:
Post a Comment