2019独角兽企业重金招聘Python工程师标准>>>

spring mvc 处理并发 spring处理并发请求_spring mvc 处理并发



spring mvc 处理并发 spring处理并发请求_apache_02

一、TOMCAT 并发请求

1、tomcat模式有 BIO、NIO、APR三种模式,操作系统对进程的线程数有限制,Windows:2000,linux:1000;Tomcat默认配置的最大请求数是150,[即150个bio线程],远超过150的最好就采取集群

2、BIO模式,即阻塞IO,默认配置。

         server.xml:<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

         每个请求都需要创建一个线程进行处理,这种模式下的并发量受到线程数量的限制,胜在模式成熟稳定,BUG极少

3、NIO模式,即非阻塞IO,JAVA NIO实现理论基础,实现较复杂,[建议可采用netty框架来快速实现]

         server.xml:<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443" />

        在性能上高于阻塞式的,每个请求也不用额外创建一个新线程进行处理,并发能力能BIO强;适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂

4、APR模式,(Apache Portable Runtime/Apache可移植运行库),是Apache HTTP服务器的支持库。当然,apr模式还需要安装 apr 、 apr-utils 、tomcat-native包

        server.xml:<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol" connectionTimeout="20000" redirectPort="8443" />,

        Tomcat将以JNI的形式调用Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地提高Tomcat对静态文件的处理性能。 Tomcat apr也是在Tomcat上运行高并发应用的首选模式。

    bio 信息: Starting ProtocolHandler ["http-bio-8080"] 2013-8-6 16:17:50 org.apache.coyote.AbstractProtocol start

    nio 信息: Starting ProtocolHandler ["http-nio-8080"] 2013-8-6 16:59:53 org.apache.coyote.AbstractProtocol start

    apr 信息: Starting ProtocolHandler ["http-apr-8080"] 2013-8-6 17:03:07 org.apache.coyote.AbstractProtocol start       



Tomcat 6.x版本从6.0.32开始就默认支持apr。 Tomcat 7.x版本从7.0.30开始就默认支持apr。 因此,所以高版本tomcat在Windows下启动的日志中看到的多是http-apr-8080-的线程日志



===========分割线,bio线程是池模式复用的,所以一个bio线程可以承载多次request请求==========================

二、spring 单例 @controller、@service

        1、spring框架controller和service默认都是单例的,那么多并发bio时,是如何实现线程安全的?    线程与栈:

             A、每当启用一个线程时,JVM就为他分配一个Java栈,栈是以帧为单位保存当前线程的运行状态。某个线程正在执行的方法称为当前方法,当前方法使用的栈帧称为当前帧,当前方法所属的类称为当前类,当前类的常量称为当前常量池。当线程执行一个方法时,它会跟踪当前常量池。
             B、每当线程调用一个Java方法时,JVM就会在该线程对应的栈中压入一个帧,这个帧自然就成了当前帧。当执行这个方法时,它使用这个帧来存储参数、局部变量、中间运算结果等等。
             C、Java栈上的所有数据都是私有的。任何线程都不能访问另一个线程的栈数据。所以我们不用考虑多线程情况下栈数据访问同步的情况。

             D、如上,则@Controller是单例模式,即一个对象只有一个实例。通过线程副本[栈]的模式实现并发访问

        2、线程副本与安全问题  线程副本通过栈和帧实现线程隔离,达到并发访问的目的,那么有没有前提呢?

成员变量则是会受到多线程调用影响的

            B、那Controller里面的service都是成员变量,会受影响么?service也是单例,其主要用来实现方法调用,就会进入帧的切换从而转变为中间结果的问题,同理单例的service的成员变量和局部变量的线程隔离性同Controller。

                PS:Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态。

 记录了AOP切面中获取request方式的原理就是据此而来

                        TransactionSynchronizationManager对资源resources采用ThreadLocal保管,就是dao的SqlSession[亦即getConnection]的由来

成员变量就被暴露在所有线程面前了,所以最好用ThreadLocal保护起来,实现线程安全。

                 PS: 描述了ThreadLocal在此种模式下的坑

三、单例应用场景

            A、有状态和无状态的对象基本概念: 

                    有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存数据,是非线程安全的。一般是prototype scope。

                    无状态对象(Stateless Bean),就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。一般是singleton scope。

                    Service和Dao就都是无状态对象,适用于单例场景,如果有资源操作的限制,就涉及同步器、锁等操作了

==========分割线,后续与单例的并发访问就无太大关系了,属于额外问题的7延伸==================

三、多线程与事务的藕断丝连

                事务管理器用于管理各个事务方法,它产生一个事务管理上下文。下文以SpringJDBC的事务管理器DataSourceTransactionManager类为例

                spring七个事务传播属性[PROPAGATION_REQUIRED等]和五个隔离级别[ISOLATION_DEFAULT 等]

                 我们知道数据库连接Connection在不同线程中是不能共享的,事务管理器为不同的事务线程利用ThreadLocal类提供独立的Connection副本。事实上,它将Service和Dao中所有线程不安全的变量都提取出来单独放在一个地方,并用ThreadLocal替换。而多线程可以共享的部分则以单实例方式存在。

                延伸问:事务个默认隔离属性和和默认传播属性是什么?以及在多线程中的影响?

========================分割线===================================