线程池原理和使用在面试中被高频问到,好比阿里的面试题。下面我们针对问题来举行回覆。
为什么要使用线程池?
线程池的使用场景有2:
1, 高并发场景:好比tomcat的处置机制,内置了线程池处置http请求;
2,异步义务处置:好比spring的异步方式革新,增添@Asyn注解对应了一个线程池;
使用线程池带来的利益有4:
1, 降低系统的消耗:线程池复用了内部的线程对比处置义务的时刻建立线程处置完毕销毁线程降低了线程资源消耗
2,提高系统的响应速度:义务不必守候新线程建立,直接复用线程池的线程执行
3,提高系统的稳固性:线程是主要的系统资源,无限制建立系统会奔溃,线程池复用了线程,系统会更稳固
4,提供了线程的可治理功效:暴露了方式,可以对线程举行调配,优化和监控
线程池的实现原理
线程池处置义务流程
当向线程池中提交一个义务,线程池内部是若何处置义务的?
先来个流程图,标识一下焦点处置步骤:
1,线程池内部会获取activeCount, 判断活跃线程的数目是否大于即是corePoolSize(焦点线程数目),若是没有,会使用全局锁锁定线程池,建立事情线程,处置义务,然后释放全局锁;
2,判断线程池内部的壅闭行列是否已经满了,若是没有,直接把义务放入壅闭行列;
3,判断线程池的活跃线程数目是否大于即是maxPoolSize,若是没有,会使用全局锁锁定线程池,建立事情线程,处置义务,然后释放全局锁;
4,若是以上条件都知足,接纳饱和处置计谋处置义务。
说明:使用全局锁是一个严重的可升缩瓶颈,在线程池预热之后(即内部线程数目大于即是corePoolSize),义务的处置是直接放入壅闭行列,这一步是不需要获得全局锁的,效率比较高。
源码如下:
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);
}
注释没保留,注释的内容就是上面画的流程图;
代码的逻辑就是流程图中的逻辑。
线程池中的线程执行义务
执行义务模型如下:
线程池中的线程执行义务分为以下两种情形:
1, 建立一个线程,会在这个线程中执行当前义务;
2,事情线程完成当前义务之后,会死循环从BlockingQueue中获取义务来执行;
代码如下:
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (int c = ctl.get();;) {
// Check if queue empty only if necessary.
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP)
|| firstTask != null
|| workQueue.isEmpty()))
return false;
for (;;) {
if (workerCountOf(c)
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateAtLeast(c, SHUTDOWN))
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 c = ctl.get();
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
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;
}
从代码中可以看到:把事情线程增添到线程池,然后释放锁,执行完提交进来的义务之后,新建的事情线程状态为启动状态;
线程池的使用
建立线程池
建立线程池使用线程池的组织函数来建立。
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数简朴翻译过来,然后做一下备注:
RejectedExecutionHandler分为4种:
Abort:直接抛出异常
Discard:静默抛弃最后的义务
DiscardOldest:静默抛弃最先入队的义务,并处置当前义务
CallerRuns:挪用者线程来执行义务
也可以自定义饱和计谋。实现RejectedExecutionHandler即可。
线程池中提交义务
线程池中提交义务的方式有2:
1,void execute(Runable) ,没有返回值,无法判断义务的执行状态。
2,Future submit(Callable) ,有返回值,可以凭据返回的Future工具来判断义务的执行状态,也可以挪用get方式来同步壅闭当前线程获取效果,或者接纳get方式的超时版本,防止壅闭超时的发生。
代码如下:
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
<T> Future<T> submit(Callable<T> task);
关闭线程池
关闭线程池方式有2:
1,shutdown();
2,shutdownNow();
两种关闭的方式区别如下表:
关闭原理都是挪用线程的interrupt()方式来中止所有的事情线程,以是无法中止的线程的义务可能永远没法终止。
只要挪用了以上两个方式,isShutdown=true;只有所有的事情线程都关闭,isTerminaed=true;
若何合理的设置线程池参数?
分如下场景,参考选择依据如下:
行列的使用推荐使用有界行列,提高系统的稳固性和预警能力。
监控线程池
场景:当线程池出现问题,可以凭据监控数据快速定位和解决问题。
线程池提供的主要监控参数:
也可以自定义监控,通过自定义线程池,实现beforeExecute,afterExecute,terminated方式,可以在义务执行前,义务执行后,线程池关闭前纪录监控数据。
小结
本篇先从使用场景和优点出发剖析了为什么要使用线程池。
然后先容了线程池中义务的执行历程,以及事情线程处置义务的两种方式。
最后先容了若何使用线程池,建立,销毁,提交义务,监控,设置合理的参数调优等方面。
posted @ 2020-04-11 23:50 李福春 阅读( ...) 谈论( ...) 编辑 珍藏 刷新谈论刷新页面返回顶部 Copyright © 2020 李福春原创不易,点赞关注支持一下吧!转载请注明出处,让我们互通有无,共同进步,迎接沟通交流。
我会连续分享Java软件编程知识和程序员生长职业之路,迎接关注,我整理了这些年编程学习的种种资源,关注民众号‘李福春连续输出’,发送'学习资料'分享给你!
Powered by .NET Core on Kubernetes ,
欢迎进入申慱官方下载!Sunbet 申博提供申博开户(sunbet开户)、SunbetAPP下载、Sunbet客户端下载、Sunbet代理合作等业务。
网友评论
最新评论
欧博会员开户欢迎进入欧博会员开户(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。我吹爆此文!!
@环球UGAPP下载
送你一枝玫瑰花。@澳洲5彩票官网(a55555.net) Prabakaran, who won the urban seat as a PKR-backed independent in the last general election and subsequently joined the party, said he is a “party man” and would obey any decision made by the leadership.我先占楼了
@环球UGAPP下载 3月20日,针对之前模糊的“战略投资者”定位,证监会进行了明确。22日晚,亚威股份(002559,SZ)抛出了定增方案,成为战投认定新规后“首例”。公司拟引入建投投资有限责任公司(以下简称建投投资)为战略投资者,并披露了原因以及后续运作。是不是还可以?
@aLLbet代理开户(www.aLLbetgame.us) 赞你一万年
欧博会员开户欢迎进入欧博会员开户(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。我吹爆此文!!
联博统计接口www.326681.com采用以太坊区块链高度哈希值作为统计数据,联博以太坊统计数据开源、公平、无任何作弊可能性。联博统计免费提供API接口,支持多语言接入。怎么这么好看
(www.huangguan.us)是一个开放皇冠即时比分、皇冠官网手机版下载、皇冠足球app下载、皇冠注册的皇冠官网平台。皇冠新现金网平台上登录线路最新、新2皇冠网址更新最快,皇冠体育APP开放皇冠会员注册、皇冠代理开户等业务。你会红的