问题:


我写了一个服务,并为每个请求分配一个线程来处理,我这样做的原因是因为基本上每个请求都是一次数据库的查询操作。我使用了一个线程池的库来减少线程的创建和销毁。


我的问题是:像这样的I/O多线程,什么才是一个好的临界点?我知道这需要一个粗略的估计值,但这个值应该是几百呢还是几千?


更新:


非常感谢你们所有的回答,看起来我需要去测试找出线程数上限,问题是:我怎么知道线程数已经到达了上限?我究竟该如何去测量?


回答:


有的人可能会说,两个线程就算是太多的线程了。我不是特别同意这种看法。


我的建议是:测试,而不是猜想。我建议把线程数设置为可配置的,并初始化为100个线程,然后运行你的软件并对它进行监控。


如果线程的使用峰值才为3,那说明100个线程就是太多了。如果一天中的大部分时间都保持在100个线程,那就将线程的数量提高到200,然后再监视其运行情况。


你确实可以让你的代码自动监控线程的使用,并在下次启动的时候自动修改配置选项,但没必要这么做。

  

详述:


我不支持经常变动你的线程池,而是尽可能的使用某一个值,你可能会问一个线程池合适的临界点是什么,现假定你的线程池可以限制线程池的最大线程数(这是一件非常好的事情)。

我写过线程池和数据库连接池,他们拥有以下最基本的特征(我认为这些对系统的性能来说是必要的):


  • 最小活动线程数

  • 最大线程数

  • 多久关闭一个未被使用的线程


第一条是为了确保线程池的最低性能标准(这些线程是一直可以被使用的)。第二条是为了限制活动线程的资源使用。第三条是在一定的时间内将线程数返回到基准的设置,以减少资源的使用。


你需要去平衡线程未被完全使用(情况A)和没有足够的工作线程(情况B)的情况。


A通常指内存的使用(栈等等),因为一个不工作的线程不会占用太多的CPU资源。B通常会延迟处理到达请求,直到有可以使用的线程。


这就是为什么要去测算,正如你遇到的这种情况,绝大部分线程需要等待数据库的响应才能运行。这就有两个主要因素影响线程的数量:


第一个因素是数据库的有效连接数。这是一个硬性的限制,除非你能通过数据库管理系统增加数据库的连接数。在这里,我假设你的数据库管理系统能够承担的数据库连接数是无限制的。(虽然,理想情况下,你也应该测量一下)


其次,线程数量应该依赖于你系统的历史运行情况。最小的线程数你应该设置为在历史最低的线程数的基础上加上A%和一个绝对的最小数值(例如,让它也可被配置,就像A一样)5。


线程池的最大数应该设置为在历史最大线程数的基础上加上B%。


你也应该监控你系统运行情况的变化,如果因为某些原因,在某一个非常重要的时刻,你的线程池使用率达到100%(这将影响你客户端的性能),这就应该增加你线程池所允许的最大线程的数量,使其再增加B%。


对于“我究竟如何去测试”的回答:


你应该明确测算当前运行(例如,等待数据库调用的返回)负载下的最大线程数量。然后增加一个安全因子,如10%(强调一下,很多人貌似把我举得例子当做了固定的建议)


此外,在生产环境下,这点也应该是需要去调节的。在刚开始的时候先估计一个值是没问题的,但是,你永远也无法预料生产环境下会产生什么情况(这就是为什么要把所有的这些都设置为运行时可配置的原因)。这就能应付各种客户端调用时所出现的不可预期的情况。


更多相关文章

  1. 多线程之死锁就是这么简单
  2. 线程池你真不来了解一下吗?
  3. LockSupport:一个很灵活的线程工具类
  4. 源码实战 | 从线程池理论聊聊为什么要看源码
  5. 多线程学习(三)那些队列可用于线程池
  6. 多线程学习(三)多线程开发带来的问题与解决方法
  7. 多线程学习(二) 多线程创建4种方式
  8. Java线程池-当任务渐增时的处理-各个参数的含义
  9. 多线程学习(一) 线程与进程的理解

随机推荐

  1. Caused by: java.lang.IllegalStateExcep
  2. RocketMQ 源码解析 —— 调试环境搭建
  3. 芋道 Spring Boot Elasticsearch 入门
  4. 我的PMP学习感悟
  5. 芋道 Spring Boot 分库分表入门
  6. 芋道 Spring Boot 多数据源(读写分离)入门
  7. Centos怎么用parted分区超过2TB硬盘
  8. 使用Android模拟器调试linux内核
  9. Find常用语法
  10. 用原生 JavaScript 实现十大 jQuery 函数