【Spring Boot】有点并发的业务都会涉及到JDK线程池

构造方法

不多说,最基础的就是构造方法。

    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;
    }
复制代码

七个参数

简单说,其实就是配置的参数。

  • corePoolSize:核心线程数大小:不管它们创建以后是不是空闲的。线程池需要保持 corePoolSize 数量的线程,除非设置了 allowCoreThreadTimeOut
  • maximumPoolSize:最大线程数:线程池中最多允许创建 maximumPoolSize 个线程。
  • keepAliveTime:存活时间:如果经过 keepAliveTime 时间后,超过核心线程数的线程还没有接受到新的任务,那就回收。
  • unitkeepAliveTime 的时间单位。
  • workQueue:存放待执行任务的队列:当提交的任务数超过核心线程数大小后,再提交的任务就存放在这里。它仅仅用来存放被 execute 方法提交的 Runnable 任务。所以这里就不要翻译为工作队列了,不要自己给自己挖坑。
  • threadFactory:线程工程:用来创建线程工厂。比如这里面可以自定义线程名称,当进行虚拟机栈分析时,看着名字就知道这个线程是哪里来的,不会懵逼。
  • handler :拒绝策略:当队列里面放满了任务、最大线程数的线程都在工作时,这时继续提交的任务线程池就处理不了,应该执行怎么样的拒绝策略。

JDK执行流程

线程池是来处理任务的,当来了一个任务,线程池的基本执行流程如下

  • JDK 线程池中如果核心线程数已经满了的话,那么后面再来的请求都是放到阻塞队列里面去,阻塞队列再满了,才会启用最大线程数。

Tomcat执行流程

如果用的是Tomcat,那么……

  • Tomcat 里面的线程池的运行过程是:如果核心线程数用完了,接着用最大线程数,最后才提交任务到队列里面去的。这样是为了保证响应时间优先。

300只是最大值,如果请求源源不断的过来,那就肯定是吃不消了

问题

10 个机器,1000 个请求并发,平均每个服务承担 100 个请求。服务器是 4 核的配置。

  • 如果是 CPU 密集型的任务,我们应该尽量的减少上下文切换,所以核心线程数可以设置为 5,队列的长度可以设置为 100,最大线程数保持和核心线程数一致。
  • 如果是 IO 密集型的任务,我们可以适当的多分配一点核心线程数,更好的利用 CPU,所以核心线程数可以设置为 8,队列长度还是 100,最大线程池设置为 10

当然,上面都是理论上的值。应该通过压测结果的对比,从而确定最合适的设置。

从4个角度考虑:

  • CPU密集型的情况。
  • IO密集型的情况。
  • 通过压测得到合理的参数配置
  • 线程池动态调整。(通过线程池监控,做到提前预警)

调优策略

一般最先是数据库扛不住压力。

  • 优化系统参数。
  • 分散压力。分库分表、读写分离
  • 引入缓存,在入口处拦截请求。
  • 削峰填谷,合理使用MQ。
  • 异步。
  • 服务熔断、服务降级。
  • 服务器扩充

作者:襄垣
链接:https://juejin.cn/post/6925309606512033799

猜你喜欢

转载自blog.csdn.net/qq_46388795/article/details/113704206
今日推荐