摘要
Servlet是线程不安全的。Servlet体系是建立在java多线程的基础之上的,它的生命周期是由Tomcat来维护的。当客户端第一次请求Servlet的时候,tomcat会根据web.xml配置文件实例化servlet;当又有一个客户端访问该servlet的时候,不会再实例化该servlet,也就是多个线程在使用这个实例。
Servlet线程池
serlvet采用多线程来处理多个请求同时访问,Tomcat容器维护了一个线程池来服务请求。线程池实际上是等待执行代码的一组线程叫做工作组线程(Worker Thread)
,Tomcat容器使用一个 调度线程来管理工作组线程(Dispatcher Thead)
。

当容器收到一个Servlet请求,Dispatcher线程从线程池中选出一个工作组线程,将请求传递给该线程,然后由该线程来执行Servlet的service方法。当这个线程正在执行的时候,容器收到另一个请求,调度者线程将从线程池中选出另外一个工作组线程来服务则个新的请求。容器并不关心这个请求是否访问的是同一个Servlet还是另一个Servlet。当容器收到对同一个Servlet的多个请求的时候,那这个servlet的service方法将在多线程中并发的执行。
多线程和单线程Servlet区别
- 多线程下每个线程对局部变量都会有自己的一份copy,这样对局部变量的修改只会影响到自己的copy而不会对别的线程产生影响,线程安全的。
- 对于实例变量来说,由于servlet在Tomcat中是以单例模式存在的,所有的线程共享实例变量。多个线程 对共享资源的访问就造成了线程不安全问题。
总结
Servlet的线程安全问题只有在大量的并发访问时才会显现出来,并且很难发现,因此在编写Servlet程序时要特别注意。线程安全问题主要是由实例变量——全局变量造成的,因此在Servlet中应避免使用实例变量。如果应用程序设计无法避免使用实例变量,那么使用同步来保护要使用的实例变量,但为保证系统的最佳性能,应该 同步可用性最小的代码路径。