0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

线程池的两个思考

科技绿洲 来源:Java技术指北 作者:Java技术指北 2023-09-30 11:21 次阅读

今天还是说一下线程池的两个思考。

池子

我们常用的线程池,

  1. JDK的ThreadPoolExecutor.
  2. CompletableFutures 默认使用了ForkJoinPool.commonPool()。
CompletableFuture.supplyAsync(()- >{ return "hello word";});
  1. 还有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线程池执行任务:

  1. 提交任务给线程池后,线程池会检查线程池中正在运行的线程数量,如果线程数量小于核心线程,则创建一个新的线程来处理任务。
  2. 如果线程池中线程数量达到和corePoolSize的大小,则将线程放入等待队列BlockingQueue中。
  3. 如果提交任务时连等待队列都已经满了的话,线程池会继续创建新的线程来处理任务,直到线程池数量达到maximumPoolSize。
  4. 如果线程数量达到了最大容量,则会执行拒绝策略。

这里需要注意直接使用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

    文章

    1316

    浏览量

    39957
  • 接口
    +关注

    关注

    33

    文章

    7985

    浏览量

    149292
  • 线程池
    +关注

    关注

    0

    文章

    54

    浏览量

    6783
  • JDK
    JDK
    +关注

    关注

    0

    文章

    80

    浏览量

    16518
  • tomcat
    +关注

    关注

    0

    文章

    27

    浏览量

    4809
收藏 人收藏

    评论

    相关推荐

    Java中的线程包括哪些

    java.util.concurrent 包来实现的,最主要的就是 ThreadPoolExecutor 类。 Executor: 代表线程的接口,有一 execute() 方法,给一
    的头像 发表于 10-11 15:33 646次阅读
    Java中的<b class='flag-5'>线程</b><b class='flag-5'>池</b>包括哪些

    线程创建的种方法

    1. 使用内置模块在使用多线程处理任务时也不是线程越多越好,由于在切换线程的时候,需要切换上下文环境,依然会造成cpu的大量开销。为解决这个问题,线程
    发表于 03-16 16:15

    两个线程和互斥锁如何形成死循环?

    两个线程两个互斥锁如何形成死锁?程序流程图如下: 程序流程图 如上图所示: t0时刻,主线程创建子线程,并初始化互斥锁mutex1、mut
    的头像 发表于 01-02 16:47 1365次阅读
    <b class='flag-5'>两个</b><b class='flag-5'>线程</b>和互斥锁如何形成死循环?

    两个线程两个互斥锁如何形成死锁

    两个线程两个互斥锁如何形成死锁? 程序流程图如下: 程序流程图 如上图所示: t0时刻,主线程创建子线程,并初始化互斥锁mutex1、mu
    的头像 发表于 12-28 09:24 2083次阅读
    <b class='flag-5'>两个</b><b class='flag-5'>线程</b>,<b class='flag-5'>两个</b>互斥锁如何形成死锁

    如何正确关闭线程

    前言本章分为两个议题 如何正确关闭线程 shutdown 和 shutdownNow 的区别 项目环境jdk 1.8 github 地址:https://github.com
    的头像 发表于 09-29 14:41 9643次阅读

    在Python中用于终止线程两个选项

      我经常被问到如何杀死一后台线程,这个问题的答案让很多人不开心: 线程是杀不死的。在本文中,我将向您展示  Python  中用于终止线程两个
    的头像 发表于 11-17 10:02 4445次阅读

    python创建线程种方法

    在使用多线程处理任务时也不是线程越多越好,由于在切换线程的时候,需要切换上下文环境,依然会造成cpu的大量开销。为解决这个问题,线程的概念
    的头像 发表于 03-16 16:15 5759次阅读

    线程线程

    线程通常用于服务器应用程序。 每个传入请求都将分配给线程池中的一线程,因此可以异步处理请求,而不会占用主
    的头像 发表于 02-28 09:53 555次阅读
    多<b class='flag-5'>线程</b>之<b class='flag-5'>线程</b><b class='flag-5'>池</b>

    如何用C++实现一线程呢?

    C++线程是一种多线程管理模型,把线程分成任务执行和线程调度部分。
    发表于 06-08 14:53 959次阅读
    如何用C++实现一<b class='flag-5'>个</b><b class='flag-5'>线程</b><b class='flag-5'>池</b>呢?

    细数线程的10

    JDK开发者提供了线程的实现类,我们基于Executors组件,就可以快速创建一线程
    的头像 发表于 06-16 10:11 551次阅读
    细数<b class='flag-5'>线程</b><b class='flag-5'>池</b>的10<b class='flag-5'>个</b>坑

    Spring 的线程应用

    我们在日常开发中,经常跟多线程打交道,Spring 为我们提供了一线程方便我们开发,它就是 ThreadPoolTaskExecutor ,接下来我们就来聊聊 Spring 的
    的头像 发表于 10-13 10:47 396次阅读
    Spring 的<b class='flag-5'>线程</b><b class='flag-5'>池</b>应用

    线程基本概念与原理

    、17、20等的新特性,简化了多线程编程的实现。 提高性能与资源利用率 线程主要解决两个问题:线程创建与销毁的开销以及
    的头像 发表于 11-10 10:24 338次阅读

    线程的基本概念

    ? 呃呃,我这么问就很奇怪,因为线程是什么我都没说,怎么会知道为什么会有线程呢?所以我打算带大家去思考
    的头像 发表于 11-10 16:37 322次阅读
    <b class='flag-5'>线程</b><b class='flag-5'>池</b>的基本概念

    线程的创建方式有几种

    线程是一种用于管理和调度线程的技术,能够有效地提高系统的性能和资源利用率。它通过预先创建一组线程并维护一工作队列,将任务提交给
    的头像 发表于 12-04 16:52 533次阅读

    什么是动态线程?动态线程的简单实现思路

    因此,动态可监控线程一种针对以上痛点开发的线程管理工具。主要可实现功能有:提供对 Spring 应用内线程
    的头像 发表于 02-28 10:42 315次阅读