Servlet生命周期及线程安全

Servlet是Java在服务器端处理用户请求的技术,其生命周期包括初始化、服务和销毁三个阶段。当首次请求时,服务器创建Servlet实例并调用init()方法;后续请求会调用service()响应,可能并发执行,因此Servlet默认非线程安全。解决线程安全问题可采用SingleThreadModel接口、避免使用成员变量或使用synchronized同步控制。
摘要由CSDN通过智能技术生成

什么是Servlet        

Servlet技术就是Java在服务器端创建响应用户请求对象的技术,被创建的对象习惯上是称为一个Servlet对象。

        Servlet就是部署在web服务器上的java程序。

 servlet的生命周期

 (1) 初始化Servlet对象。Servlet对象第一次被请求加载时,服务器初始化这个Servlet对象,即创建一个Servlet对象,对象调用init()方法完成必要的初始化工作。
(2)诞生的Servlet对象再调用service()方法响应客户的请求。
(3)当服务器关闭时,调用destroy()方法,消灭Servlet对象。

public void init(ServletConfig config) throws ServletException

        第一次调用某个Servlet时,它的init方法将会被调用。在Servlet的一个生命周期中,仅会执行一次init方法。

 public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {

        HttpServletRequest  request;
        HttpServletResponse response;

        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }
        service(request, response);
    }

该service方法将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse,然后调用参数为Http的service方法。

 protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    // Invalid date header - proceed as if none was set
                    ifModifiedSince = -1;
                }
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);

        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);

        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);

        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);

        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);

        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);

            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }


        当请求发送到某个Servlet时,该Servlet的service方法都将被调用一次。service方法默认服务功能是调用与HTTP请求的方法相对应的doGet或doPost方法,doPost的方法实质上调用的还是doGet方法。

public void destroy()


        当服务器停止服务,卸载Servlet时,该方法将被调用。

其中init()方法只执行了一次。

service()方法反复执行,只有是有请求就会执行该方法。

destroy()方法也只执行了一次。 

Servlet线程安全

servlet不是线程安全的,从上面Servlet的生命周期可以看出,当第一次调用Servlet的时候,tomcat会根据web.xml配置文件实例化servlet,当后面又有请求访问该servlet的时候,不会再实例化该servlet。

servlet默认是单例模式,需要考虑线程安全的问题,在web容器中只创建一个实例,所以多个线程同时访问的时候是不安全的。

package com.dao.view;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/demoServlet")
public class demoServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    private int count=10;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		if(count>0) {
			count--;
		}
	}

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

在代码中如果是多线程在调用doGet()方法,在count临界的时候就可能会出现,由于多线程造成的错误。

解决方案

(1)让当前Servlet实现javax.servlet.SingleThreadModel 接口。

(2)在Servlet中不要使用成员变量,使用局部变量:
  每个用户的每个请求都会调用service方法,而局部变量在service方法中,每一次都是新的空间。
(3)使用synchronized 关键字能保证一次只有一个线程

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值