当前位置: 首页 > news >正文

JDK线程池中到底该设置多少线程数才比较合适

JDK线程池中到底该设置多少线程数呢?

  • 为什么线程数太多会导致频繁的上下文切换呢?
  • 通过判断业务是CPU密集型还是IO密集型去决定线程数的大小
    • 1、CPU密集型
    • 2、IO密集型
  • 如何根据业务特点去计算线程数的大小呢?

很多小伙伴觉得,线程池中设置多少线程数,或者说创建的JDK线程池中核心线程数、最大线程数该设置多少比较合适,一般都是通过CPU核数去计算的,但是需要根据处理业务的特点去进行设计

  • 线程数太少会导致程序不能充分利用系统资源、容易让阻塞队列里边的任务出现饥饿的现象
  • 线程数太多会导致频繁的线程上下文切换,消耗cpu资源并且会占用更多的内存
  • IO操作是数据的交互(input跟output)需要从硬盘中读取数据或者网络请求获取数据,将数据读到内存后让CPU处理,读数据的过程中不会占用CPU,但是当前线程需要通过IO获取数据,所以必须等到IO操作结束后再交由CPU处理,此时会导致线程阻塞。也就是说IO操作不会占用CPU但是会阻塞线程

为什么线程数太多会导致频繁的上下文切换呢?

基于JDK线程池,它的工作原理就是维护两个集合,workersSet和taskQueue,workersSet中的worker不断从任务队列中取出任务去执行,如果线程数太多

  • 核心线程取不到阻塞队列中的任务,底层通过LockSupport.park(),将当前线程状态从Runnable转换为WAITING,此时会导致线程上下文切换。
  • 非核心线程数也就是救急线程数(最大线程数-核心线程数)也会有线程状态从Runnable转换为WAITING的过程,并且在一定时间内结束线程

通过判断业务是CPU密集型还是IO密集型去决定线程数的大小

1、CPU密集型

  • 需要CPU大量计算,很少有IO操作比如查询数据库、Redis或者RPC、HTTP调用
  • 通常采用CPU核数+1能够实现最优的CPU利用率,+1是保证当线程由于缺页故障(操作系统)或其他原因导致暂停时,额外的这个线程就能顶上,保证CPU时钟周期不被浪费

2、IO密集型

  • 有很多查询数据库或者Redis、RPC、HTTP请求,包括读取文件等
  • 执行IO请求时,不占用CPU但是占用线程,此时就需要多个线程去提高利用率
  • 线程数 = 核数 * 期望CPU利用率 * 总时间(CPU计算时间+等待时间)/ CPU 计算时间

如何根据业务特点去计算线程数的大小呢?

业务中如果出现到使用线程池的场景,无非就是出现高并发或者任务执行时间长,需要通过多个线程去提高CPU利用率

  1. 高并发、执行任务时间短的业务

    • 执行任务时间短,我们不需要去考虑是CPU密集型还是IO密集型,反正执行时间短

    • 线程数可以设置为CPU核数+1,减少线程上下文切换

    • 针对JDK线程池,核心线程数跟可以为0,创建出来的全部都是救急线程,可以根据一定时间的空闲让线程自动结束,最大线程数根据需要进行设计,阻塞队列可以采用同步阻塞队列,但是最大线程数必须设计合理,因为使用同步阻塞队列,没有线程来取,任务是放不进去的,可以通过调高最大线程数,或者换成LinkedBlockingQueue

    • // JDK线程池
      new ThreadPoolExecutor(0, 10,
                             60L, TimeUnit.SECONDS,
                             new SynchronousQueue<Runnable>());
      
  2. 并发不高,任务执行时间长,要区分成CPU密集型或者IO密集型

    • CPU密集型

      • 假如业务执行时间主要花费在计算上,那么就是CPU密集型任务,那么还是要减少线程数,减少线程上下文切换
    • IO密集型

      • 假如业务执行时间集中在IO操作室,那么就是IO密集型任务,因为IO操作不会占用CPU,通过加大线程数,让CPU处理更多的业务,充分利用CPU

      • JDK线程池,可以不需要设置救急线程,适用于任务量已知,相对耗时的任务

      • new ThreadPoolExecutor(nThreads, nThreads,
                               0L, TimeUnit.MILLISECONDS,
                               new LinkedBlockingQueue<Runnable>());
        
  • 并发高,任务执行时间长的业务,解决这种类型的业务除了要设计好线程池,还需要设计好整体的架构,这里提供一些思路
  • 并发请求同步转异步,设计线程池
  • 如果查询数据库时间长
    • 是否可以优化sql,例如:limit查询要避免无效回表查询,连表查询慢可以通过设计中间表等
    • 适当创建索引,通过记录慢查询、explain查看执行计划,判断索引是否失效
    • sql不能够在优化,但是查询速度还是很慢,看看单表数据是否太大,超过200w就算数据量很多,或者数据库的QPS超过2000,就需要进行分库分表,或者搭建主从集群,利用ShardingJDBC或者Mycat进行分库分表,通过实现读写分离减轻主库压力,提高查询效率
    • 网络带宽太小
  • 优化代码结构,减少不必要的类创建或者查询
  • 设计多级缓存
  • 最终才是通过增加服务器,通过横向拓展的方式去提高整个系统的QPS

以上便是JDK线程池设置线程数大小的全部内容,如有解析不当欢迎在评论区指出!

相关文章:

  • 数据库补充笔记2
  • 使用 pushd 和 popd 实现快速切换目录
  • JSONP 教程
  • Oracle数据库dump文件的导入与导出及创建表空间
  • 淘宝十年资深架构师吐血总结淘宝的数据库架构设计和采用的技术手段。
  • 南大通用数据库-Gbase-8a-学习-32-gccli客户端
  • Linux的scp、rsync、以及集群分发脚本、ssh配置免密登录
  • 【计算机视觉 | 目标检测】锚点预匹配(Anchor pre-matching)的理解
  • 智联物联分享之物联网协议MQTT简述,MQTT协议特点
  • Echarts立体柱状图
  • SpringBoot定时任务@Scheduled注解详解
  • Gen-LaneNet论文精读总结
  • Spring Cloud Alibaba全家桶——微服务网关Gateway组件
  • 基于微信PC端小程序抓包方法
  • SQL Server 实现邮件发送功能(配置步骤及存储过程源码)
  • Android交互
  • Angular 2 DI - IoC DI - 1
  • JavaScript函数式编程(一)
  • JavaScript类型识别
  • JS实现简单的MVC模式开发小游戏
  • Lsb图片隐写
  • mongo索引构建
  • PHP 的 SAPI 是个什么东西
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • Vue 2.3、2.4 知识点小结
  • Vue--数据传输
  • 第十八天-企业应用架构模式-基本模式
  • 关于springcloud Gateway中的限流
  • 解析带emoji和链接的聊天系统消息
  • 前端自动化解决方案
  • 数据结构java版之冒泡排序及优化
  • 栈实现走出迷宫(C++)
  • 智能合约开发环境搭建及Hello World合约
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • 湖北分布式智能数据采集方法有哪些?
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • $.each()与$(selector).each()
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (12)Hive调优——count distinct去重优化
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (pojstep1.1.2)2654(直叙式模拟)
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (附源码)ssm学生管理系统 毕业设计 141543
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (四)JPA - JQPL 实现增删改查
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)用.Net的File控件上传文件的解决方案
  • .NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
  • .net 设置默认首页
  • .NET设计模式(7):创建型模式专题总结(Creational Pattern)
  • .NET业务框架的构建
  • @column注解_MyBatis注解开发 -MyBatis(15)
  • [ 蓝桥杯Web真题 ]-Markdown 文档解析
  • [ 隧道技术 ] 反弹shell的集中常见方式(四)python反弹shell
  • [AIGC] SQL中的数据添加和操作:数据类型介绍