内容简介:写这篇文章的起因源于笔者对一个小问题的不断追溯,并非是先去看类似的文章然后总结得到,这样做的好处就是在于具有目的性,找答案时也会更有兴趣。这个小问题大家平时在springMVC项目中基本都会碰到:生产日志down下来发现经常会有穿插打印两个接口日志的现象,经过分析发现第一个request执行到一部分还没执行完时第二个request又上来了,因为2个request对应的接口都会调用一些其它系统或者创建,关闭sqlSession这类需要等待耗时的操作,在某个接口执行到这种等待期时,另一个接口就会在这个间隙继续往
引言
写这篇文章的起因源于笔者对一个小问题的不断追溯,并非是先去看类似的文章然后总结得到,这样做的好处就是在于具有目的性,找答案时也会更有兴趣。这个小问题大家平时在springMVC项目中基本都会碰到:生产日志down下来发现经常会有穿插打印两个接口日志的现象,经过分析发现第一个request执行到一部分还没执行完时第二个request又上来了,因为2个request对应的接口都会调用一些其它系统或者创建,关闭sqlSession这类需要等待耗时的操作,在某个接口执行到这种等待期时,另一个接口就会在这个间隙继续往下执行,最终造成日志一会打印A接口的执行,一会打印B接口的执行。基于此现象,笔者产生了以下猜想。
正文
两个接口的执行是否对应了2个线程?如果是这样,是否意味着容器每收到一个请求都会创建1个线程?
有个显而易见的东西,某个request没执行完,也就是没返回response前系统是可以处理其它请求的。
笔者想要确定出现这种情况时,是否是两个不同的线程在分别跑两个接口,想通过测试搞清楚,原理是在两个接口执行过程中把线程地址打出来,通过比较是否一样确定是否是2个线程,将原来的springMVC项目找到2个查询接口。
在A接口中间某个程序段加上如下代码块
logger.info("A1>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"+Thread.currentThread());
try {
Thread.sleep(new Long(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("A2>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"+Thread.currentThread());复制代码
在B接口中间某个程序段加上如下代码块
logger.info("B1>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"+Thread.currentThread());
try {
Thread.sleep(new Long(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("B2>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"+Thread.currentThread());复制代码
然后写了2个测试类,用来模拟http请求,测试类1向A接口发请求,测试类2向B接口发请求
使用tomcat启动项目,然后执行测试类1,间隔3秒左右启动测试类2,等待了几秒钟,测试类1,2都分别收到了回复,查看日志,发现打印顺序如下
...... A1>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Thread[http-apr-8090-exec-2,5,main] ...... B1>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Thread[http-apr-8090-exec-4,5,main] ...... A2>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Thread[http-apr-8090-exec-2,5,main] ...... B2>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Thread[http-apr-8090-exec-4,5,main] ......复制代码
由打印日志不难发现,的确是2个线程
那么能否据此推测说容器每接收到1个请求就会创建1个线程呢?答案是否定的
以tomcat为例,暂不考虑其它容器,经过大量的资料查询,发现和tomcat的运行模式有关系,tomcat有3种运行模式,分别是
- bio模式
即每1个请求,tomcat都会创建1个线程,现在的tomcat基本都用线程池处理,类似数据库的连接池,提前创建好一定数量的连接,比起请求来了再创建省很多时间。很容易想到,如果并发量很大时,就会需要很多线程,内存肯定很容易溢出的。tomcat配置文件中的Connector节点下默认maxConnections=maxThreads,如果是bio模式,如果想要改变maxThreads(默认75),只需要配置maxThreads
- nio模式
maxConnections>maxThreads,即nio模式相对bio模式同等情况下减少了线程数,笔者的理解就是通过某种优化最大化压榨CPU,把时间片都更好利用起来,这里也说明了1个请求未必对应1个线程,之前做过netty项目其通讯就是nio模式,这里附上1篇高质量讲解NIO模式的文章: www.jianshu.com/p/76ff17bc6… ,有兴趣可以看下
- apr 模式
和nio模式类似,主要区别在于处理静态资源的能力更强
如何查看你的项目是什么运行模式?
查看启动日志,会发现类似这样的东西:
信息: Initializing ProtocolHandler ["http-nio-8090"] 四月 10, 2019 9:16:19 下午 org.apache.tomcat.util.net.NioSelectorPool getSharedSelector 信息: Using a shared selector for servlet write/read 四月 10, 2019 9:16:19 下午 org.apache.coyote.AbstractProtocol init 信息: Initializing ProtocolHandler ["http-bio-8443"] 复制代码
从日志看出,tomcat在8090端口以nio模式运行,8443端口以bio模式运行
3种运行模式的适用情况:
bio方式基本被淘汰了
nio方式适用于连接数多,连接时间短的架构,比如QQ,微信
apr方式使用于连接数多, 连接时间长的架构,比如相册服务器,QQ空间相册
如果不指定,tomcat有默认的运行模式,7.0.30以后默认是apr模式
运行模式修改:
平时大家应该很少涉及,这篇文章主要是用来理解的,修改很简单,大把教程,如有需要自行百度
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 如何在后台(脱离模式下)运行Docker容器
- Flink 集群运行原理兼部署及Yarn运行模式深入剖析-Flink牛刀小试
- Spark 系列(五)—— Spark 运行模式与作业提交
- GoPlus 0.6.40 发布,支持线上运行模式
- 记录Hadoop3.1.1 伪分布式运行模式
- Unity 3D 的 Shader 运行时状态及渲染模式问题
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Effective JavaScript
David Herman / Addison-Wesley Professional / 2012-12-6 / USD 39.99
"It's uncommon to have a programming language wonk who can speak in such comfortable and friendly language as David does. His walk through the syntax and semantics of JavaScript is both charming and h......一起来看看 《Effective JavaScript》 这本书的介绍吧!