首页 > 其他分享 >如何证明Servlet是单例的?

如何证明Servlet是单例的?

时间:2023-05-25 15:45:19浏览次数:35  
标签:web 证明 线程 单例 MyServlet message Servlet out

Servlet是web体系里面最重要的部分,下面罗列几道常见的面试题,小伙伴们一定要好好记住哈。

1.Servlet是单例的吗,如何证明?

Servlet一般都是单例的,并且是多线程的。如何证明Servlet是单例模式呢?很简单,重写Servlet的init方法,或者添加一个构造方法。然后,在web.xml中配置。如:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  

  <servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>web.MyServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>

</web-app>

然后是MyServlet

public class MyServlet extends HttpServlet{
 
 public MyServlet(){
  System.out.println("MyServlet构造函数调用了");
 }

 @Override
 public void init() throws ServletException {
  System.out.println("MyServlet初始化");
 }
 
 

}

启动Tomcat,不管你访问多少次这个Servlet,init方法和构造器都只会执行1次。

2.如何让Servlet变成多例

方法1.实现 SingleThreadModel 接口(不推荐,官方已经将这个接口废弃)

public class MyServlet extends HttpServlet implements SingleThreadModel{
 
 public MyServlet(){
  System.out.println("MyServlet构造函数调用了");
 }

 @Override
 public void init() throws ServletException {
  System.out.println("MyServlet初始化");
 }

}

SingleThreadModel的意思是“单线程模式”,如果servlet实现了该接口,会确保不会有两个线程同时执行servlet的service方法。

servlet容器通过同步化访问servlet的单实例来保证,也可以通过维持servlet的实例池,对于新的请求会分配给一个空闲的servlet。源码中,最多会生成20个实例。

方法2. 在web.xml中多配置一个Servlet

哪怕是同一个Servlet,你在web.xml中配置几个,就会有几个实例。

3.你能证明Servlet线程不安全吗?

Servlet默认是线程不安全的!

Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。

当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类。

当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例。

Servlet容器会自动使用线程池等技术来支持系统的运行。

当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不一致。

所以在用Servlet构建的Web应用时如果不注意线程安全的问题,会使所写的Servlet程序有难以发现的错误。

下面举一个例子来说明,为什么Servlet是线程不安全的。

public class MyServlet extends HttpServlet{
 
 String message;

 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  message = req.getParameter("message");
  PrintWriter out = resp.getWriter();
  //故意延时5秒钟,使得下一次请求过来的时候,message的值还没有返回就被覆盖了
  try {
   Thread.sleep(5000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  out.write(message);
  out.flush();
  out.close();
  
 }


}

打开两个浏览器,分别访问:

http://localhost:8080/web/hello?message=jack

http://localhost:8080/web/hello?message=rose

因为有5秒的延时,所以可能就会出现第一个Servlet还没返回呢,第二个Servlet就进来了。于是,把message的值给冲掉了。如下图

石锤了,Servlet是线程不安全的。

4.你怎么设计一个线程安全的Servlet?

1.最直接的办法,就是用上面的SingleThreadModel接口

既然单例会有共享实例变量导致线程不安全的问题,那就改成多例的呗。

但是,这个接口都已经被官方废弃了,这就说明官方也不推荐这么做。原因很简单,那就是这样一来会有很多个实例,性能的代价太大了。

  1. 用同步锁

这也是非常容易想到的办法,把当前对象锁起来,不返回不给其他用户插入(怎么有点怪怪的?)

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 
 synchronized(this){
  message = req.getParameter("message");
  PrintWriter out = resp.getWriter();
  //故意延时5秒钟,使得下一次请求过来的时候,message的值还没有释放
  try {
   Thread.sleep(5000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  out.write(message);
  out.flush();
  out.close();
 
 }
 
}

这样的代价就是等待时间更长了,参考火车上的的卫生间,这就是同步锁。

  1. 尽量别用实例变量,用局部变量代替

标签:web,证明,线程,单例,MyServlet,message,Servlet,out
From: https://www.cnblogs.com/skyblue-li/p/17431463.html

相关文章

  • Java笔记(八):单例模式
    懒汉式懒汉式单例模式在第一次调用的时候进行实例化。1.适用于单线程环境(不推荐)此方式在单线程的时候工作正常,但在多线程的情况下就有问题了。如果两个线程同时运行到判断instance是否为null的if语句,并且instance的确没有被创建时,那么两个线程都会创建一个实例,此时类型Singlet......
  • 之前servlet可用,之后修改,调用又表现为空白
    之前能够显示。看自己代码发现自己上层发完,无处理,没进行跳转。 修改后可以 ......
  • 《设计模式之禅》Singleton_Pattern--单例模式
    单例模式这个模式是很有意思,确实很有意思的,而且比较简单,但是我还是要说因为它使用的是如此的广泛,如此的有人缘,单例就是单一、独苗的意思,那什么是独一份呢?你的思维是独一份,除此之外还有什么不能山寨的呢?我们举个比较难复制的对象:皇帝(就是那个天子)中国的历史上很少出现两个皇帝并存的......
  • Expected MultipartHttpServletRequest: is a MultipartResolver configured方案。
    //1.报错:ExpectedMultipartHttpServletRequest:isaMultipartResolverconfigured?//2.解决<!--uploadify文件上传组件--><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId>......
  • 黑马优化Servlet
    问题:平常我们编写servlet的时候,经常会一个java文件写一个方法调用这样很麻烦,会写一堆的Servlet文件解决方法:编写基本的baseservlet,之后其他的文件采用/Brand/*调用该方法,替换HttpServlet,根据请求的最后一段路径来进行方法分发BaseServlet.java文件packagecom.hailei.web.ser......
  • gcd 证明
    gcd$gcd(a,b)$表示a与b的最大公约数。heregcd证明设有$gcd(a,b)=d(a>b)$,则$d|a$、$d|b$(也就是d既是a的因数也是b的因数)。设有$k=\lfloor\frac{a}{b}\rfloor$、$r=a\modb$,则$a=bk+r$。举个栗子,因为$a=5b+1=5\times2+1=11$,则\[\begin{c......
  • 上下文管理者(ServletContext)
    作用1.获取全局初始化参数2.资源共享(servlet通信)能让上下文呢的Servlet相互关联起来3.获取资源文件生命周期创建服务器启动的时候会为每个项目创建一个servletContext上下文对象,servleContext是项目的一个引用销毁在服务器关闭或者移除项目的时候servletContext销毁获取方......
  • Java-Servlet解析
    前言从事Javaweb项目开发有一段时间了,一直不理解它是怎么一回事,后来查询资料发现这里面涉及到几个东西,分别是tomcat、JavaEE中13个规范之一的servlet、以及springMVC。于是就去学习了一下,发现这里里面都是围绕这servlet进行的操作。于是就有了今天的这个总结。Servlet定义Servl......
  • ServletContext接口详解
    1. ServletContext是什么?  14 *  ServletContext是接口,是Servlet规范中的一员。2. ServletContext是谁实现的?14 *  Tomcat服务器(WEB服务器)实现了ServletContext接口。 *  public class org.apache.catalina.core.ApplicationContextFacade implements ServletCont......
  • controller是单例模式还是多例模式?spring默认的是单例模式,那么如何保证线程安全
    controller是单例模式还是多例模式在Java中,Controller既可以是单例模式,也可以是多例模式,这取决于具体的实现方式。在单例模式中,Controller只会被实例化一次,多个线程共享同一个实例。这样可以节约系统资源,提高系统性能。但是在多线程环境下,如果不加以保护,可能会出现线程安全的问......