关于线程池开发的几个问题

hurukawatinami
  • 13

问题描述

最近在研究线程池的相关内容,因为没有在实际开发中使用过线程池,所以特提出以下几个问题,望高手解答。

题目描述

问题1、什么场景下使用线程池,主要解决什么问题?

问题2、一个线程池,设置参数coreSize=5,maxSize=10,blockQueueSize=10,依次提交6个比较耗时的任务,线程池是如何执行的?

问题3、场景模拟:一个支付场景,A接口需要调用微信支付接口完成支付任务,调用微信支付接口被放在一个线程池中执行,假如微信接口的超时时间是2s,A接口的qps大概是100,如何设置线程池参数比较合适?如果涉及到突发流量的场景,如何设置?

回复
阅读 2.3k
3 个回答

首先最直接的,代码中存在 new Thread().start 这类的硬编码,甚至是在 for 循环中调用,这类代码强烈要求改为线程池。

场景:当遇到需要异步执行任务的时候可用线程池,或者是批量执行某个任务,需要提高单线程的执行效率可考虑换为多线程(但需要考虑共享资源及锁带来的影响)

主要解决以下问题:

  • 线程是稀缺资源,不能频繁的创建,应当复用。
  • 解耦作用;线程的创建于执行完全分开,方便维护。
  • 线程池提高了各种监控、同步转异步等功能。

线程池的执行过程简单来说分为以下几步:

  • 线程池预热(加锁)。
  • 预热完毕,充分利用队列缓存任务。
  • 超过队列容量继续创建线程(加锁),不会超过 maxSize
  • 退出线程池。

这几步,具体过程建议查看这几篇:


线程池中涉及到一些耗时任务,比如这里的调用微信最大为 2s,说明同一时刻不是所有线程都在执行,有部分会在等待微信接口的响应;所以可以适当增加线程池的数量。

A 接口的 QPS 要求为 100 ,意味着当同一时刻有 100 个请求过来时需要都能接收处理并响应,假设这个接口中最耗时的任务为调微信;所以调用微信这里的线程池中的阻塞队列最小得为 100 ,才能缓冲最坏情况(大家都在等待微信返回时),同时 A接口还能正常向上游响应。

至于突发流量,一般都是在入口处做缓冲,这里其实和线程池关系不大(有可能在调微信之前的业务逻辑就撑不住了);所以一般可以在入口加上限流、也可用 MQ 来削峰。

解1、线程池解决重复创建和销毁线程的开销,因为在JVM框架下,线程是比较重的资源,重复的创建和销毁只会影响系统性能。
解2、简单点,当coreSize空闲时候,直接在线程池里面运行,达到coreSize的时候,丢到队列里面排队,当达到coreSize,然后队列也满的时候,新建线程然后放到线程池里面。当线程池达到maxSize时,指定丢弃策略。另外,如果你的队列是无界队列,那么就忽视掉maxSize的存在吧,任务会堆积到内存耗尽。
解3、超时时间是2s,就假如你一次调用算2S吧,那么一个线程1S执行0.5次调用,如果你qps100,那线程数就是200,当然你超时时间不代表真正业务执行时间,具体看你真实执行时间。如果突发流量,看你系统设计,一方面可以通过线城池调整资源,另外可以引入分布式队列,多机部署你的服务,再有适当调整你的业务,在量大的时候,对前端的支付通知,不要通过同步方法,加一些提示说业务量大,支付结果会有延迟,就可以。
再有就是如果线程开太多,也不好,操作系统调度时候做线程上下文切换,也是一种消耗,如果可以做异步调用的地方就做异步,可以了解下NIO、EPOLL、NETTY等的知识。

宣传栏