今天还是说一下线程池的两个思考。
池子
我们常用的线程池,
CompletableFuture.supplyAsync(()- >{ return "hello word";});
- 还有Tomcat中的线程池
org.apache.tomcat.util.threads.TaskQueue
org.apache.tomcat.util.threads.ThreadPoolExecutor
线程池维护多个线程,等待监督管理者分配可并发执行的任务。这种做法,一方面避免了处理任务时创建销毁线程开销的代价,另一方面避免了线程数量膨胀导致的过分调度问题,保证了对内核的充分利用。
JDK 线程池
public ThreadPoolExecutor(
int corePoolSize, //核心线程数
int maximumPoolSize,//最大线程数
long keepAliveTime, //大于核心线程数量的线程存活时间,如果没有新任务就会关闭
TimeUnit unit, // 时间单位
BlockingQueue< Runnable > workQueue, //线程等待队列
ThreadFactory threadFactory,//创建线程的工厂
RejectedExecutionHandler handler//拒绝策略
) {
JDK线程池执行任务:
- 提交任务给线程池后,线程池会检查线程池中正在运行的线程数量,如果线程数量小于核心线程,则创建一个新的线程来处理任务。
- 如果线程池中线程数量达到和corePoolSize的大小,则将线程放入等待队列BlockingQueue中。
- 如果提交任务时连等待队列都已经满了的话,线程池会继续创建新的线程来处理任务,直到线程池数量达到maximumPoolSize。
- 如果线程数量达到了最大容量,则会执行拒绝策略。
这里需要注意直接使用LinkedBlockingQueue阻塞队列作为线程池会存在一个问题,当workcount > corePool时优先进入队列排队, 当请求并发过多时会导致请求缓慢,队列太长可能会出现内存溢出(先排队再涨线程池)
Tomcat线程池
下面时Tomcat线程池的构造方法
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue< Runnable > workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
this.ctl = new AtomicInteger(ctlOf(-536870912, 0));
this.mainLock = new ReentrantLock();
this.workers = new HashSet();
this.termination = this.mainLock.newCondition();
this.submittedCount = new AtomicInteger(0);
this.lastContextStoppedTime = new AtomicLong(0L);
this.lastTimeThreadKilledItself = new AtomicLong(0L);
this.threadRenewalDelay = 1000L;
if (corePoolSize >= 0 && maximumPoolSize > 0 && maximumPoolSize >= corePoolSize && keepAliveTime >= 0L) {
if (workQueue != null && threadFactory != null && handler != null) {
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
this.prestartAllCoreThreads();
} else {
throw new NullPointerException();
}
} else {
throw new IllegalArgumentException();
}
}
Tomcat主要针对web接口请求,不能因为LinkedBlockingQueue的排队导致接口出现大量延迟和缓慢, 从而使用了tomcat的TaskQueue,TaskQueue继承了JDK的LinkedBlockingQueue 并扩展了JDK线程池的功能。
主要有一下几点优化:
- Tomcat的ThreadPoolExecutor使用的TaskQueue,是无界的LinkedBlockingQueue,但是通过taskQueue的offer方法覆盖了LinkedBlockingQueue的offer方法,修改了线程池增长规则,使得线程池能在任务较多的情况下增长线程池数量。(先涨线程池再排队。)
- Tomcat的ThreadPoolExecutor改写了execute方法,当任务被reject时,捕获异常,会强制入队
public void execute(Runnable command, long timeout, TimeUnit unit) {
this.submittedCount.incrementAndGet();
try {
this.executeInternal(command);
} catch (RejectedExecutionException var9) {
if (!(this.getQueue() instanceof TaskQueue)) {
this.submittedCount.decrementAndGet();
throw var9;
}
TaskQueue queue = (TaskQueue)this.getQueue();
try {
if (!queue.force(command, timeout, unit)) {
this.submittedCount.decrementAndGet();
throw new RejectedExecutionException(sm.getString("threadPoolExecutor.queueFull"));
}
} catch (InterruptedException var8) {
this.submittedCount.decrementAndGet();
throw new RejectedExecutionException(var8);
}
}
}
那个线程池适合
我们看看AI如何回复
了不起认为大多数情况下使用JDK的线程池就够用了,如果觉得线程数据处理不过来,需要多一点线程直接增加核心线程数量设置就可以了。针对资源比较紧张,对线程使用代价比较高时可以考虑。
tomcat对线程池做过优化,也必然是有一定的考量,对于线程资源的使用频率比较高的情况下可以使用。
-
内核
+关注
关注
3文章
1372浏览量
40273 -
接口
+关注
关注
33文章
8573浏览量
151007 -
线程池
+关注
关注
0文章
57浏览量
6844 -
JDK
+关注
关注
0文章
81浏览量
16592 -
tomcat
+关注
关注
0文章
27浏览量
4853
发布评论请先 登录
相关推荐
评论