线程池的核心线程数该怎么设置

这篇具有很好参考价值的文章主要介绍了线程池的核心线程数该怎么设置。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

为什么要用线程池?线程池中的线程可以重复利用,避免了重复创建线程造成的资源开销。在线程的执行时间比较短,任务比较多的时候非常适合用线程池。

线程池原理及使用

代码示例

// threadPoolExecutor 最好定义一个全局的,不用每次重建线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5));

public testThreadPool() {
    // 方式1 不需要返回值
    threadPoolExecutor.submit(new Runnable() {
        @Override
        public void run() {
            // 处理相关业务
        }
    });
    
    // 方式2 有返回值
    Future<String> submit = threadPoolExecutor.submit(new businessWorker("param"));
}


class businessWorker implements Callable<String> {
    public businessWorker(String param) {
    }
    @Override
    public String call() throws Exception {
        
        return null;
    }
}

线程池执行步骤

线程池核心线程数和最大线程数怎么设置,jvm,java,开发语言

  1. 如果运行的线程少于核心线程,会尝试去开启一个新的核心线程(addWorker),如果有空间的核心线程,也不会去使用,而是去创建一个新的核心线程,直到核心线程创建满。核心线程创建满了,线程去队列中取任务。
  2. 如果运行的线程数等于核心线程数,任务则进入队列等待核心线程调用。
  3. 如果队列已满,则去创建非核心线程。
  4. 如果非核心线程也饱和了,则进入拒绝策略

参数说明

corePoorSize:核心线程数
maximumPoorSize:最大线程数–核心线程数+非核心线程数
keepAliveTime:非核心线程允许空闲时间,超过则非核心线程销毁
unit:keepAliveTime单位
workQueue:保存任务的阻塞队列
threadFactory:创建线程的工厂
hander:线程池饱和的处理方式(拒绝策略)

接下来根据这几个参数做进一步研究

核心线程数、最大线程数、队列大小

核心线程数、最大线程数、队列大小应该设置成多少合适,设置是否合理直接关系到线程池的处理能力。参考网上的说法要根据业务判断是CPU密集型还是IO密集型
CPU密集型:就会JVM自己内部处理的一些逻辑,额外的IO操作很少
IO密集型:可以理解为经常要和数据库交互,产生的IO操作比较多

CPU密集型核心线程数:CPU核数(逻辑核) + 1
IO密集型核心线程数:2 * CPU核数(逻辑核)

我们大部分JAVA WEB项目是IO密集型

上面其实就是一个理想状态的理论值,在实际应用中还会受其它影响,比如一台服务器不可能只有这一个应用,这一个应用中也会有其它线程。所以这个核心线程数的设置并不会十分准确,还要在线上使用时来调试这些参数。

首先要通过压测来设置出一个较为合理的参数。然后简单做一个线程池的数据监控,根据这些监控数据及线上的运行情况,可以在对线程数做一下适当的调整。线程池中提供了一些数据,可供我们调用

线程池核心线程数和最大线程数怎么设置,jvm,java,开发语言

public HashMap<String, Object> getPoolInfo() {
    poolInfo.put("activeCount", threadPoolExecutor.getActiveCount());
    poolInfo.put("completedTask", threadPoolExecutor.getCompletedTaskCount());
    poolInfo.put("poolSize", threadPoolExecutor.getPoolSize());
    poolInfo.put("queueSize", threadPoolExecutor.getQueue().size());
    poolInfo.put("taskCount", threadPoolExecutor.getTaskCount());
    return poolInfo;
}

class AbortPolicyCustom implements RejectedExecutionHandler
{
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        log.info("线程处理异常");
        Integer unCompletedTask = Integer.parseInt(String.valueOf(poolInfo.get("unCompletedTask") == null ? 0 : poolInfo.get("unCompletedTask")));
        poolInfo.put("unCompletedTask", unCompletedTask + 1);
    }
}
{
    "activeCount":0,
    "taskCount":1000,
    "queueSize":0,
    "poolSize":100,
    "completedTask":1000,
    "unCompletedTask": 0
}

taskCount: 请求过来的总任务数
poolSize:当前线程池的线程数
completeTaskCount:已完成的任务数
activeCount:当前正在运行的线程数
getQueue().size():可以获取当前队列中的任务数
unCompletedTask: 未完成任务数(需要通过拒绝策略自定义实现)

经验总结:

  1. 如果业务经常用
    要求响应时间越快越好,可以适当将核心线程数和最大线程数调大一点,队列不用设置太大。这样既能提高响应,也不会浪费线程资源。
    不要求响应时间,队列可以设置大一点。

  2. 如果业务不常使用
    核心线程数可以设置小一点,最大线程数可以调成2倍核心线程数,这样如果核心线程不够用的话,可以创建非核心线程,待任务执行完后,到达空闲等待时间后销毁非核心线程,只保留了少数核心线程数,这样也不会浪费线程资源。

  3. 如果批量处理大量任务
    不宜将核心线程数设置的太大,设置的太大可能会引起线程的上下文切换带来的问题,也降低了处理速度,可以适当将队列设置大一点,不要求响应时间,慢慢处理就好了,注意做好拒绝策略处理,避免任务丢失。

拒绝策略

总共有4种拒绝策略

  1. AbortPolicy:抛出异常(默认)
  2. CallerRunsPolicy:提交任务的线程自己执行
  3. DisCardOldestPolicy:把老的任务丢掉
  4. DiscardPolicy:什么都没干,直接丢掉任务

经验来说,大多数情况使用默认的抛出异常即可,这样保证即使任务丢失后,也能做好后续处理。

public void testThreadPool() {
    long l = System.currentTimeMillis();

    try {
        threadPoolExecutor.submit(new Runnable() {
            @Override
            public void run() {
                handleMsg(l);
            }
        });
    } catch (Exception e) {
        log.info("任务处理异常:{}", e);
        Integer unCompletedTask = Integer.parseInt(String.valueOf(poolInfo.get("unCompletedTask") == null ? 0 : poolInfo.get("unCompletedTask")));
        poolInfo.put("unCompletedTask", unCompletedTask + 1);
    }
}

如果第二个策略,让主线程自己执行,任务可以不丢失,但是如果出现大量任务被拒绝的话,主线程性能会直线下降。文章来源地址https://www.toymoban.com/news/detail-717787.html

到了这里,关于线程池的核心线程数该怎么设置的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 面试官:Spring Boot 最大连接数和最大并发数是多少?问倒一大片!

    每个Spring Boot版本和内置容器不同,结果也不同,这里以Spring Boot 2.7.10版本 + 内置Tomcat容器举例。 在SpringBoot2.7.10版本中内置Tomcat版本是9.0.73,SpringBoot内置Tomcat的默认设置如下: Tomcat的连接等待队列长度,默认是100 Tomcat的最大连接数,默认是8192 Tomcat的最小工作线程数,默认

    2024年02月08日
    浏览(33)
  • Python开启线程和线程池的方法

    1、通过用户慢慢递增来进行性能压测,观察QPS(即每秒的响应请求数,也即是最大吞吐能力。),响应时间 2、根据公式计算:服务器端最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间) * cpu数量 3、单用户压测,查看CPU的消耗,然后直接乘以百分比,再进行压测,一般这

    2024年02月03日
    浏览(39)
  • JMeter中同步定时器与线程组中线程数和Ramp-Up的关系

    1. Ramp-Up值为线程组生成相应线程数的准备时间,例如1s内准备完成200个线程,线程准备间隔时间为0.005s 2. 如果无同步定时器, 则无论 Ramp-Up 设置为多大值都会立即发出请求 3. 同步定时器的超时时间, 是向线程组发送相应模拟用户数的时间 例如:     线程组设置的线程数为10,

    2024年02月16日
    浏览(25)
  • 【Linux】线程终结篇:线程池以及线程池的实现

    linux线程完结 文章目录 前言 一、线程池的实现 二、了解性知识 1.其他常见的各种锁 2.读者写者问题 总结 什么是线程池呢? 线程池一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行

    2024年02月12日
    浏览(28)
  • 聊聊线程池的预热

    本文主要研究一下线程池的预热 java/util/concurrent/ThreadPoolExecutor.java ThreadPoolExecutor定义了prestartCoreThread,用于启动一个核心线程 java/util/concurrent/ThreadPoolExecutor.java prestartAllCoreThreads用于启动所有的核心线程 ThreadPoolExecutor提供了prestartCoreThread方法,用于启动一个核心线程,提供了

    2024年02月08日
    浏览(29)
  • 线程池的执行流程

    如果所示,就是线程池的执行过程,可以分为三个主要步骤: 1.提交任务后会首先进行当前工作线程数与核心线程数的比较,如果当前工作线程数小于核心线程数,则直接调用 addWorker() 方法创建一个核心线程去执行任务; 2.如果工作线程数大于核心线程数,即线程池核心线程

    2023年04月09日
    浏览(28)
  • Java线程池的入门

    一、线程池的优势 1.降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗。 2.提高系统相应速度,当有任务到达时,通过复用已存在的行程,无需等待新线程的创建便能立刻执行。 3.方便线程并发数的管控,因为线程若是无限制创建,可能会导致内存

    2024年02月08日
    浏览(36)
  • python------线程池的应用

    在python中经常会使用异步,线程池,进程池,解决io操作,在爬虫中并不建议使用进程池(消耗过大) 目标:会使用线程池 1:导入 我们可以看到了只有在demo1完全运行完毕才会运行demo2,这个时候是单任务 2:基本使用方法 我们可以看到这时候2个线程的一起跑 3:线程池的基本使用步骤  

    2024年02月15日
    浏览(29)
  • 线程池的五种状态

    1、RUNNING 状态说明:线程池处于RUNNING状态时,能够接收新任务以及对已添加的任务进行处理。 状态切换:线程池的初始状态为RUNNING。换句话说线程池一旦被创建,就处于RUNNING状态,且线程池中的任务数为0 2、SHUTDOWN 状态说明:线程池处于SHUTDOWN状态时,不接收新任务,但能

    2023年04月09日
    浏览(64)
  • Java多线程之线程池的参数和配置

    在Java多线程编程中,线程池是一种常见的技术,用于管理线程的创建和销毁。线程池中的线程可以被重复利用,从而减少了线程的创建和销毁的开销,提高了程序的性能。在Java中,线程池的参数和配置非常重要,不同的参数和配置会影响线程池的性能和行为。 Java线程池的主

    2024年02月16日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包