内容简介:写这篇文章的起因源于笔者对一个小问题的不断追溯,并非是先去看类似的文章然后总结得到,这样做的好处就是在于具有目的性,找答案时也会更有兴趣。这个小问题大家平时在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 运行时状态及渲染模式问题
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。