接触了一小段时间的servlet,以下就总结一下关于servlet的两个方面的知识,一个是模板方法的应用。另外一个是servlet多线程产生的原因。

1. 模板方法设计模式

定义一个操作中的算法的骨架。而将步骤延迟到子类中。

模板方法使得子类能够不改变一个算法的结构就可以重定义算法的某些特定步骤。

2. Servlet中模板方法的应用

模板方法在servlet中的应用的类图

当client请求一个servlet的时候首先被调用的是service方法。Service方法就是定义骨架的方法,在service方法中会依据HTTP请求的类型(GET,POST还是其它)来调用详细的doGet和doPost等方法;即实际的处理委派给了doGet和doPost等方法。这些子类的方法来终于处理浏览器的请求。以下是HttpServlet对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 = req.getDateHeader(HEADER_IFMODSINCE);
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);
}
}

3. servlet并非严格的依照模板方法来设计的

我们常说详细问题详细分析。在这里也是。servlet 讲模板方法的精髓应用到了,可是却没有全然依照模板方法设计。

3.1 子类能够重写service()方法

模板方法模式是通过把不变的行为搬移到超类。去除了子类中的反复代码。所以超类中的模板方法普通情况下是不会被重写的。模板方法同意子类又一次定义算法的某些     步骤。而不改变算法的结构。可是在servlet中的service方法中是能够被子类重写的。当子类重写了service方法之后就破坏掉了原本定义好的模板方法。

3.2 doGet和doPost方法有默认的实现

在HttpServlet类中对于这两个被子类详细实现的方式是有实现的。

以下是HttpServlet对于这两个实现的代码

 protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}

这些说明在使用设计模式的时候并非生搬硬套,而是依据详细的情况灵活变动。可是其本质是不变的。

4.  为什么会出现线程安全问题

在学习servlet过程中一直听到的一个问题就是线程问题。学习的资料中提到servlet是多线程。不安全的。

servlet是由web容器管理的,当请求这个servlet的时候。web容器会依据web.xml中的配置实例化这个servlet。

当再次请求这个servlet的时候不会再实例化此servlet而是多线程的使用第一次请求的时候实例化的servlet。也就是一个servlet仅仅实例化一次。

当面对多个请求的时候web容器就会使用多线程来处理这些请求。

以下的图形是servlet多线程的结构图形

从图中能够看出,当容器收到一个请求servlet的请求的时候会从线程池中分出一个工作线程来处理这个请求,当有另外一个请求的时候会从线程池中分出另外一个工作线程来处理这个请求。所以假设多个用户同一时候请求同一个servlet,那么在容器中就会出现一个servlet对象的service方法并发运行。多线程是共享资源的,当他们并发运行的时候就非常有可能出现訪问资源冲突问题。

这样的处理请求的方式就是我们常常说的单实例多线程的处理方式。

以下是自己查找到的一个作者:http://blog.csdn.net/zljjava/article/details/6887266从内存的角度来分析的servlet的多线程问题。

假设有兴趣的话能够看看。

从内存中看一下这个问题能够总结以下的两种图形。当中一张是我们都知道JMM模型图

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveV9sb3ZlX2Y=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

另外一张是多个用户请求同一个servlet的多线程运行的过程是:

主内存中的实例变量是在多个线程之间共享的。每一个线程在自己的工作线程中拷贝自己须要的实例变量到自己的缓存中。就如同上面图形中的A,当线程1改动了A,可是线程2中的A还是主存中的样子,并没有立即同步到线程2和线程3中就会出现线程安全问题。

5. 总结

对于servlet的单实例多线程问题知道的原因就能够对症下药的找解决方式了。

主要是针对变量要注意。对于模板方法能够看到我们的应用非常多可是也要注意活学活用。

servlet之模板方法和多线程的更多相关文章

  1. Spring MVC:DispatchServlet类

    Spring MVC架构 Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就已包含在Spring框架中.传统的模型层被拆分为了业务层(Service)和数据访问层 ...

  2. Servlet 单例多线程

    Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在 ...

  3. Servlet单实例多线程模式

    http://kakajw.iteye.com/blog/920839 前言:Servlet/JSP技术和ASP.PHP等相比,由于其多线程运行而具有很高的执行效率.由于Servlet/JSP默认是以 ...

  4. servlet单例多线程

    Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在 ...

  5. 对于多线程下Servlet以及Session的一些理解

    今天,小伙伴突然问到了Servlet是不是线程安全的问题.脑子当时一卡壳,只想到了单实例多线程.这里做一些总结. Servlet体系是建立在Java多线程的基础之上的,它的生命周期是由Tomcat来维 ...

  6. Servlet 单例多线程【转】

    源地址:Servlet 单例多线程 Servlet如何处理多个请求访问?Servlet容器默认是采用单实例多线程的方式处理多个请求的:1.当web服务器启动的时候(或客户端发送请求到服务器时),Ser ...

  7. [转]Servlet 单例多线程

    Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在 ...

  8. Servlet 单例多线程详解(六)

    一.Servlet 单例多线程 Servlet如何处理多个请求访问?Servlet容器默认是采用单实例多线程的方式处理多个请求的:1.当web服务器启动的时候(或客户端发送请求到服务器时),Servl ...

  9. Http协议&Servlet

    http协议 针对网络上的客户端 与 服务器端在执行http请求的时候,遵守的一种规范. 其实就是规定了客户端在访问服务器端的时候,要带上哪些东西, 服务器端返回数据的时候,也要带上什么东西. 版本 ...

随机推荐

  1. centos无法安装vmvare-tools的问题

    不要使用 vmware 自带的 tools, 版本太老了. 从这里下载:https://github.com/rasa/vmware-tools-patches.git 直接下载或者使用下面的命令: ...

  2. Patterns-Flyweight

    最近在组里讨论设计模式,第一个是享元模式. 自己贴了一篇这个文章:http://www.cnblogs.com/rush/archive/2011/10/01/2197785.html 感觉这篇讲的不 ...

  3. 用rz,sz命令在windows和linux之间传输文件(转)

    转自http://www.linuxmine.com/178.html有很多人没有听说过ZModem协议,更不知道有rz/sz这样方便的工具: 下面一段是从SecureCRT的帮助中copy的: ZM ...

  4. Linxu 监控命令总结

    free –m [root@web1476 ~]# free        total       used       free     shared    buffers     cached M ...

  5. 匿名类型 使用泛型T linq返回dynamic类型的匿名实体 如何把匿名类型.GetType()返回的对象传进泛型里面 EF实体查询出的数据List<T>转DataTable出现【DataSet 不支持 System.Nullable<>】的问题

    [100分]紧急求助:LinQ下使用IQueryable<T>如何将返回类型<T>使用匿名类型 问题描述如下:我有一个方法如下:public IQueryable Dissen ...

  6. IDirect3DDevice9::SetTexture的stage参数

    HRESULT IDirect3DDevice9::SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture) 其中Stage并不是“阶段”的意思 ...

  7. FPGA的图像处理技术

    最近一段时间一直在研究基于FPGA的图像处理,乘着EEPW这个机会和大家交流一下,自己也顺便总结一下.主要是为了大家对用FPGA做图像处理有个感性的认识,如果真要研究的话就得更加深入学习了.本人水平有 ...

  8. [git]git命令行自动补齐

    1. 下载Git-completion.bash github地址:https://github.com/markgandolfo/git-bash-completion.git 2. copy到用户 ...

  9. iOS 图片的属性

    UIViewContentModeScaleToFill UIViewContentModeScaleAspectFit UIViewContentModeScaleAspectFill UIView ...

  10. 说说Java中的资源文件的读取

    最近在看spring的资源获取时发现JDK里存在几种不同方式的资源获取,因比较混乱特地总结起来帮助和我一样混乱的人理解.下面是我项目的类结构图,在 src/main/java 下有两个类 Resour ...