在我们日常业务开发过程中,或多或少都会用到并发的功能。那么在用到并发功能的过程中,就肯定会碰到下面这个问题
网站建设哪家好,找创新互联!专注于网页设计、网站建设、微信开发、成都微信小程序、集团企业网站建设等服务项目。为回馈新老客户创新互联还提供了连山免费建站欢迎大家使用!
并发线程池到底设置多大呢?
通常有点年纪的程序员或许都听说这样一个说法 (其中 N 代表 CPU 的个数)
这个说法到底是不是正确的呢?
其实这是极不正确的。那为什么呢?
首先我们从反面来看,假设这个说法是成立的,那我们在一台服务器上部署多少个服务都无所谓了。因为线程池的大小只能服务器的核数有关,所以这个说法是不正确的。那具体应该怎么设置大小呢?
假设这个应用是两者混合型的,其中任务即有 CPU 密集,也有 IO 密集型的,那么我们改怎么设置呢?是不是只能抛硬盘来决定呢?
那么我们到底该怎么设置线程池大小呢?有没有一些具体实践方法来指导大家落地呢?让我们来深入地了解一下。
Little's Law(利特尔法则)
一个系统请求数等于请求的到达率与平均每个单独请求花费的时间之乘积
假设服务器单核的,对应业务需要保证请求量(QPS):10 ,真正处理一个请求需要 1 秒,那么服务器每个时刻都有 10 个请求在处理,即需要 10 个线程
同样,我们可以使用利特尔法则(Little’s law)来判定线程池大小。我们只需计算请求到达率和请求处理的平均时间。然后,将上述值放到利特尔法则(Little’s law)就可以算出系统平均请求数。估算公式如下
*线程池大小 = ((线程 IO time + 线程 CPU time )/线程 CPU time ) CPU数目**
具体实践
通过公式,我们了解到需要 3 个具体数值
请求消耗时间
Web 服务容器中,可以通过 Filter 来拦截获取该请求前后消耗的时间
- public class MoniterFilter implements Filter {
- private static final Logger logger = LoggerFactory.getLogger(MoniterFilter.class);
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
- ServletException {
- long start = System.currentTimeMillis();
- HttpServletRequest httpRequest = (HttpServletRequest) request;
- HttpServletResponse httpResponse = (HttpServletResponse) response;
- String uri = httpRequest.getRequestURI();
- String params = getQueryString(httpRequest);
- try {
- chain.doFilter(httpRequest, httpResponse);
- } finally {
- long cost = System.currentTimeMillis() - start;
- logger.info("access url [{}{}], cost time [{}] ms )", uri, params, cost);
- }
- private String getQueryString(HttpServletRequest req) {
- StringBuilder buffer = new StringBuilder("?");
- Enumeration
emParams = req.getParameterNames(); - try {
- while (emParams.hasMoreElements()) {
- String sParam = emParams.nextElement();
- String sValues = req.getParameter(sParam);
- buffer.append(sParam).append("=").append(sValues).append("&");
- }
- return buffer.substring(0, buffer.length() - 1);
- } catch (Exception e) {
- logger.error("get post arguments error", buffer.toString());
- }
- return "";
- }
- }
CPU 计算时间
CPU 计算时间 = 请求总耗时 - CPU IO time
假设该请求有一个查询 DB 的操作,只要知道这个查询 DB 的耗时(CPU IO time),计算的时间不就出来了嘛,我们看一下怎么才能简洁,明了的记录 DB 查询的耗时。
通过(JDK 动态代理/ CGLIB)的方式添加 AOP 切面,来获取线程 IO 耗时。代码如下,请参考:
- public class DaoInterceptor implements MethodInterceptor {
- private static final Logger logger = LoggerFactory.getLogger(DaoInterceptor.class);
- @Override
- public Object invoke(MethodInvocation invocation) throws Throwable {
- StopWatch watch = new StopWatch();
- watch.start();
- Object result = null;
- Throwable t = null;
- try {
- result = invocation.proceed();
- } catch (Throwable e) {
- t = e == null ? null : e.getCause();
- throw e;
- } finally {
- watch.stop();
- logger.info("({}ms)", watch.getTotalTimeMillis());
- }
- return result;
- }
- }
CPU 数目
逻辑 CPU 个数 ,设置线程池大小的时候参考的 CPU 个数
- cat /proc/cpuinfo| grep "processor"| wc -l
总结
合适的配置线程池大小其实很不容易,但是通过上述的公式和具体代码,我们就能快速、落地的算出这个线程池该设置的多大。
不过最后的最后,我们还是需要通过压力测试来进行微调,只有经过压测测试的检验,我们才能最终保证的配置大小是准确的。
网页名称:到底如何设置Java线程池的大小?
转载源于:http://www.csdahua.cn/qtweb/news43/53493.html
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网