如何证明Servlet是单例的?

这篇具有很好参考价值的文章主要介绍了如何证明Servlet是单例的?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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();
 
 }
 
}

这样的代价就是等待时间更长了,参考火车上的的卫生间,这就是同步锁。文章来源地址https://www.toymoban.com/news/detail-458701.html

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

到了这里,关于如何证明Servlet是单例的?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Controller是单例还是多例?

    Controller是单例还是多例? controller默认是单例的,不要使用非静态的成员变量,否则会发生数据逻辑混乱。正因为单例所以不是线程安全的。 我们下面来简单的验证下: 我们首先访问 http://localhost:8080/testScope,得到的答案是1; 然后我们再访问 http://localhost:8080/testScope2,得到

    2024年02月13日
    浏览(44)
  • 不是单例的单例——巧用ClassLoader

    本文通过如何将一个单例类实例化两次的案例,用代码实践来引入 Java 类加载器相关的概念与工作机制。理解并熟练掌握相关知识之后可以扩宽解决问题的思路,另辟蹊径,达到目的。 单例模式是最常用的设计模式之一。其目的是保证一个类在进程中仅有一个实例,并提供一

    2024年02月04日
    浏览(30)
  • 【设计模式学习1】什么是单例模式?单例模式的几种实现。

    单例模式是在内存中只创建一个对象的模式,它保证一个类只有一个实例。 如上图所示,多线程情况下,在时刻T,线程A和线程B都判断single为null,从而进入if代码块中都执行了new Single()的操作创建了两个对象,就和我们当初的单例初衷相悖而行。 1、第一次判空目的:为了缩

    2024年02月15日
    浏览(54)
  • 单例的例子

    2024年02月07日
    浏览(31)
  • QT单例的简单使用

    单例的.h文件 单例的.cpp文件 使用单例的.cpp代码

    2024年02月16日
    浏览(30)
  • 【设计模式】单例模式、“多例模式”的实现以及对单例的一些思考

    单例模式是设计模式中最简单的一种,对于很多人来说,单例模式也是其接触的第一种设计模式,当然,我也不例外。这种设计模式在学习、面试、工作的过程中广泛传播,相信不少人在面试时遇到过这样的问题:“说说你最熟悉的集中设计模式”,第一个脱口而出的就是单

    2024年02月07日
    浏览(48)
  • 设计模式——C++11实现单例模式(饿汉模式、懒汉模式),与单例的进程

    本文将介绍单例模式,使用C++11实现多个版本的单例模式,分析各自的优缺点。最后提及如何实现一个单例的进程。 单例模式属于创建型模式,提供了一种创建对象的方式。 单例模式确保一个类只有一个实例。通过一个类统一地访问这个实例。 思想:将构造函数设置为私有

    2024年02月09日
    浏览(48)
  • 面试题百日百刷-HBase中HTable API有没有线程安全问题,在程序是单例还是多例?

    锁屏面试题百日百刷,每个工作日坚持更新面试题。 请看到最后就能获取你想要的, 接下来的是今日的面试题:   1. HBase内部机制是什么? Hbase是一个能适应联机业务的数据库系统 物理存储:hbase的持久化数据是将数据存储在HDFS上。 存储管理:一个表是划分为很多region的,

    2023年04月08日
    浏览(36)
  • day42-servlet下拉查询/单例模式

    1.Servlet 实现下拉查询(两表) 2. 单例模式 1.实战 1.1  创建工程,准备环境... 1.2  接口 1.3  重写方法 1.4  servlet 1.5  list.jsp list.jsp 详解 2.单例模式 2.1  饿汉模式:在程序加载时直接创建对象(私有化,静态化),并创建公有的静态的(public static)get方法;其他类需要使用时

    2024年02月16日
    浏览(37)
  • 什么是单页应用程序?如何选择及架构、优势和挑战

    单页面应用程序(Web应用程序或网站)仅加载单个页面。然后,当用户与Web服务器交互时,它使用从Web服务器获取的新内容重写页面,而不是为每次交互加载新页面。 单页面应用程序是一种网站解决方案,可以直接在浏览器中呈现JavaScript代码。它确保用户在浏览网站时不会重新

    2024年02月12日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包