面试题,Servlet 线程安全吗?

Servlet的工作原理:

首先客户发送一个请求,Servlet是调用service()方法对请求进行响应的,通过源代码可见,service()方

法中对请求的方式进行了匹配,选择调用doGet,doPost等这些方法,然后再进入对应的方法中调用逻辑层的方法,实现对客户的响应。在Servlet接口和GenericServlet中是没doGet,doPost等等这些方法的,HttpServlet中定义了这些方法,但是都是返回error信息,所以,我们每次定义一个Servlet的时候,都必须实现doGet或doPost等这些方法。

  每一个自定义的Servlet都必须实现Servlet的接口,Servlet接口中定义了五个方法,其中比较重要的三个方法涉及到Servlet的生命周期,分别是上文提到的init(),service(),destroy()方法。GenericServlet是一个通用的,不特定于任何协议的Servlet,它实现了Servlet接口。而HttpServlet继承于GenericServlet,因此HttpServlet也实现了Servlet接口。所以我们定Servlet的时候只需要继承HttpServlet即可。

  Servlet接口和GenericServlet是不特定于任何协议的,而HttpServlet是特定于HTTP协议的类,所以HttpServlet中实现了service()方法,并将请求ServletRequest,ServletResponse强转为HttpRequest和HttpResponse。在Servlet整个生命周期中是由Tomcat来维护的,当客户端第一次发起请求的时候,会根据web.xml文件中的配置实例化一个Servlet,而在以后客户端的每一次请求都会使用该实例来处理后续的工作,知道Tomcat停止该项目,这个Servlet才会被销毁,所占用的资源才会释放。

  当客户端发来多个请求的时候,Servlet将采用多线程来解决这样的并发,而在Tomcat本身也维护了一个线程池来处理并发。线程池实际上是等待执行代码的一组线程叫做工作组线程(Worker Thread),Tomcat容器使用一个调度线程来管理工作组线程(Dispatcher Thead)。


Servlet线程安全问题很大部分是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。

有什么方法能够解决这个问题呢?答案是将实例变量编程局部变量,

为什么局部变量为什么不会被共享呢?

 多线程下每个线程对局部变量都会有自己的一份copy,这样对局部变量的修改只会影响到自己的copy而不会对别的线程产生影响,线程安全的。

Java 内存模型中,方法中的临时变量是在栈上分配空间,而且每个线程都有自己私有的栈空间,所以它们不会影响线程的安全。

但是对于实例变量来说,由于servlet在Tomcat中是以单例模式存在的,所有的线程共享实例变量。多个线程对共享资源的访问就造成了线程不安全问题。


猜你喜欢

转载自blog.csdn.net/qq_27828675/article/details/80566319