首页 > 其他分享 >Servlet生命周期和线程安全

Servlet生命周期和线程安全

时间:2022-12-24 17:00:12浏览次数:42  
标签:生命周期 方法 init 调用 线程 Servlet public


本文目录

  • ​​一、Servlet生命周期​​
  • ​​1、生命周期四个阶段​​
  • ​​1.1、实例化​​
  • ​​1.2、初始化​​
  • ​​1.3、服务​​
  • ​​1.4、销毁​​
  • ​​1.5、Servlet执行流程​​
  • ​​二、Servlet特性​​
  • ​​1、线程安全问题​​
  • ​​2、如何保证线程安全​​

Servlet生命周期和线程安全_java

一、Servlet生命周期

1、生命周期四个阶段

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

  • Servlet 初始化后调用 init () 方法。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 销毁前调用 destroy() 方法。
  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

现在让我们详细讨论生命周期的方法。

1.1、实例化

  当用户第一次访问Servlet时,由容器调用Servlet的构造器创建具体的Servlet对象。也可以在容器启动之后立刻创建实例。使用如下代码可以设置Servlet是否在服务器启动时就创建。

实例化只执行一次。

public LifeServlet() {
System.out.println("1、完成实例化");
}

1.2、初始化

  在初始化阶段,init()方法会被调用。在后续每次用户请求时不再调用。因此,它是用于一次性初始化,就像 Applet 的 init 方法一样。

  Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。

  当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。

init()方法只被执行一次

public void init() throws ServletException {
super.init();
System.out.println("2、完成初始化");
}

1.3、服务

  当客户端有一个请求时,容器就会将请求ServletRequest与响应ServletResponse对象转给Servlet,以参数的形式传给service方法。

  每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。

service()方法会执行多次

public void service(ServletRequest request, 
ServletResponse response)
throws ServletException, IOException{
}

  doGet() 和 doPost() 方法是每次服务请求中最常用的方法。下面是这两种方法的特征。

doGet() 方法

  GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。

public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet 代码
}

doPost() 方法

  POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。

public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet 代码
}

1.4、销毁

  当Servlet容器停止或者重新启动都会引起销毁Servlet对象并调用destroy方法

  destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

  在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。

destroy()方法执行一次

public void destroy() {
super.destroy();
System.out.println("4、销毁了");
}

1.5、Servlet执行流程

Servlet生命周期和线程安全_java_02

  1. 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
  2. Servlet 容器在调用 service() 方法之前加载 Servlet。
  3. 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

/**
* 演示Servlet的生命周期
* 1、实例化
* 2、init:初始化
* 3、service:服务
* 4、destory:销毁
*/

@WebServlet("/LifeServlet")
public class LifeServlet extends HttpServlet {

public LifeServlet() {
System.out.println("1、完成实例化");
}

@Override
public void init() throws ServletException {
super.init();
System.out.println("2、完成初始化");
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("3、就绪中");
response.getWriter().append("Served at:").append(request.getContextPath());
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

@Override
public void destroy() {
super.destroy();
System.out.println("4、销毁了");
}
}

二、Servlet特性

1、线程安全问题

  Servlet在访问之后,会执行实例化操作,创建一个Servlet对象。而我们Tomcat容器可以同时多个线程并发访问同一个Servlet,如果在方法中对成员变量做修改操作,就会有线程安全问题。

2、如何保证线程安全

  1. synchronize
  • 将存在线程安全问题的代码放到同步代码块中
  1. 实现SingleThreadModel接口
  • servlet实现SingleThreadMode接口后。每个线程都会创建servlet实例,这样每个客户端请求就不存在共享资源的问题,但是servlet响应客户端的效率太低,所以已经淘汰。
  1. 尽可能使用局部变量

    将全局变量public boolean status;改为局部变量boolean status = true;
public class TestServlet extends HttpServlet{

// public boolean status;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
boolean status = true;
String cmd = req.getParameter("cmd");
if (cmd.contains("Calculator")) {
status = false;
try {
Thread.sleep(1000);
}catch (Exception e){

}
}

if (!status) {
return;
}
if (cmd.contains("Calculator")){
resp.getWriter().write(cmd);
}
}
}

标签:生命周期,方法,init,调用,线程,Servlet,public
From: https://blog.51cto.com/u_15740516/5967176

相关文章

  • 02.关于线程你必须知道的8个问题(上)
    大家好,我是王有志,欢迎来到《Java面试都问啥?》的第一篇技术文章。这个系列会从Java部分开始,接着是MySQL和Redis的内容,同时会继续更新数据结构与算法的部分,这样在第一阶段,我......
  • 多线程必知必会的知识点
    说说阻塞队列的实现:可以参考ArrayBlockingQueue的底层实现(锁和同步都行);如果队列是空的,消费者会一直等待,当生产者添加元素时候,消费者是如何知道当前队列有元素的呢?如果让你来......
  • 线程通信分解3
    【1】  【2】packagecom.msb.test11;/***@author:liu*日期:15:42:06*描述:IntelliJIDEA*版本:1.0*/publicclassProduct{//商品类//......
  • 多线程
    多线程什么是进程?什么是线程?进程是一个应用程序(1个进程是一个软件)。线程是一个进程中的执行场景/执行单元。一个进程可以启动多个线程。对于java程序来说,当在DOS命令......
  • 【并发技术系列】「多线程并发编程」技术体系和并发模型的基础探究(夯实基础)
    让我们通过本篇文章一同进入并发编程技术的世界里面,相信通过这篇文文章一定会对话你的并发技术体系有一定帮助以及夯实你的基础功底。基本概念并发concurrency并行paralleli......
  • 线程通信问题分解2
    【1】利用同步代码块解决问题packagecom.msb.test10;importcom.sun.media.sound.RIFFInvalidDataException;/***@author:liu*日期:16:02:52*描述:Intel......
  • Java中线程的6种状态详解
    java.lang.Thread.State枚举类中定义了六种线程的状态,可以调用线程Thread中的getState()方法获取当前线程的状态。publicenumState{NEW,RUNNABLE,......
  • Day19_06_Vue教程之Vue实例的生命周期
    Vue教程之Vue实例的生命周期一.什么是生命周期Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载DOM、渲染→更新→渲染、卸载等一系列过程,我们......
  • 线程通信问题分解1
    packagecom.msb.test10;/***@author:liu*日期:15:42:06*描述:IntelliJIDEA*版本:1.0*/publicclassProduct{//商品类//品牌privateStr......
  • 线程通信问题 引入
    应用场景:生产者和消费者问题假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费如果仓库中没有产品,则生产者将产品放入仓库,否则停止......