servlet多线程

Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例。 这样,当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不一致。所以在用Servlet构建的Web应用时如果不注意线程安全的问题,会使所写的Servlet程序有难以发现的错误。

实例变量不正确的使用是造成Servlet线程不安全的主要原因。下面针对该问题给出了三种解决方案并对方案的选取给出了一些参考性的建议。

  2、同步对共享数据的操作

  使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段,在本论文中的Servlet可以通过同步块操作来保证线程的安全。同步后的代码如下:

…………
Public class Concurrent Test extends HttpServlet { …………
Username = request.getParameter ("username");
");
}
}
}
  

……
}
}


  对上面的三种方法进行测试,可以表明用它们都能设计出线程安全的Servlet程序。但是,如果一个Servlet实现了SingleThreadModel接口,Servlet引擎将为每个新的请求创建一个单独的Servlet实例,这将引起大量的系统开销。SingleThreadModel在Servlet2.4中已不再提倡使用;同样如果在程序中使用同步来保护要使用的共享的数据,也会使系统的性能大大下降。这是因为被同步的代码块在同一时刻只能有一个线程执行它,使得其同时处理客户请求的吞吐量降低,而且很多客户处于阻塞状态。另外为保证主存内容和线程的工作内存中的数据的一致性,要频繁地刷新缓存,这也会大大地影响系统的性能。所以在实际的开发中也应避免或最小化 Servlet 中的同步代码;在Serlet中避免使用实例变量是保证Servlet线程安全的最佳选择。从Java 内存模型也可以知道,方法中的临时变量是在栈上分配空间,而且每个线程都有自己私有的栈空间,所以它们不会影响线程的安全。



补充:

servlet存在的多线程问题
实例变量:   实例变量是在堆中分配的,并被属于该实例的所有线程共享,所以不是线程安全的.
JSP系统提供的8个类变量:
JSP中用到的OUT,REQUEST,RESPONSE,SESSION,CONFIG,PAGE,PAGECONXT是线程安全的,APPLICATION在整个系统内被使用,所以不是线程安全的.
局部变量:   局部变量在堆栈中分配,因为每个线程都有它自己的堆栈空间,所以是线程安全的.
静态类:       静态类不用被实例化,就可直接使用,也不是线程安全的.
外部资源:   在程序中可能会有多个线程或进程同时操作同一个资源(如:多个线程或进程同时对一个文件进行写操作).

此时也要注意同步问题. 使它以单线程方式执行,这时,仍然只有一个实例,所有客户端的请求以串行方式执行。这样会降低系统的性能
initialValue(); // 返回该线程局部变量的当前线程的初始值                   
void set(Object value); // 设置当前线程的线程局部变量副本的值
  ThreadLocal有3个方法,其中值得注意的是initialValue(),该方法是一个protected
的方法,显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始
值,这个方法是一个延迟调用方法,在一个线程第1次调用get()或者set(Object)时才执行
,并且仅执行1次。ThreadLocal中的确实实现直接返回一个null:
protected Object initialValue() { return null; }
  ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,
在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。比如下面的示例实现:

public class ThreadLocal
{
 private Map values = Collections.synchronizedMap(new HashMap());
 public Object get()
 {
  Thread curThread = Thread.currentThread();
  Object o = values.get(curThread);
  if (o == null && !values.containsKey(curThread))
  {
   o = initialValue();
   values.put(curThread, o);
  }
  return o;
 }

 public void set(Object newValue)
 {
  values.put(Thread.currentThread(), newValue);
 }

 public Object initialValue()
 {
  return null;
 }
}

  当然,这并不是一个工业强度的实现,但JDK中的ThreadLocal的实现总体思路也类似于此。
ThreadLocal的使用
  如果希望线程局部变量初始化其它值,那么需要自己实现ThreadLocal的子类并重写该
方法,通常使用一个内部匿名类对ThreadLocal进行子类化,比如下面的例子,SerialNum类
为每一个类分配一个序号:
public class SerialNum
{
 // The next serial number to be assigned
 private static int nextSerialNum = 0;
 private static ThreadLocal serialNum = new ThreadLocal()
 {
  protected synchronized Object initialValue()
  {
   return new Integer(nextSerialNum++);
  }
 };

 public static int get()
 {
  return ((Integer) (serialNum.get())).intValue();
 }
}

  SerialNum类的使用将非常地简单,因为get()方法是static的,所以在需要获取当前线
程的序号时,简单地调用:

int serial = SerialNum.get(); 即可。
  在线程是活动的并且ThreadLocal对象是可访问的时,该线程就持有一个到该线程局部
变量副本的隐含引用,当该线程运行结束后,该线程拥有的所以线程局部变量的副本都将失
效,并等待垃圾收集器收集。
如果你需要进行多个线程之间进行通信,
则使用同步机制;如果需要隔离多个线程之间的共享冲突,可以使用ThreadLocal,这将极
大地简化你的程序,使程序更加易读、简洁。

public class ConnectionDispenser {
  private static class ThreadLocalConnection extends ThreadLocal {
           public Object initialValue() {
                  return DriverManager.getConnection(ConfigurationSingleton.getDbUrl());
           }
   }
    private ThreadLocalConnection conn = new ThreadLocalConnection();
    public static Connection getConnection() {
            return (Connection) conn.get();
   }
}

注意:
理论上来说,ThreadLocal是的确是相对于每个线程,每个线程会有自己的ThreadLocal。但是上面已经讲到,一般的应用服务器都会维护一套线程池。因此,不同用户访问,可能会接受到同样的线程。因此,在做基于TheadLocal时,需要谨慎,避免出现ThreadLocal变量的缓存,导致其他线程访问到本线程变量。

时间: 2024-08-29 20:05:25

servlet多线程的相关文章

servlet多线程同步问题

Servlet/JSP技术和ASP.PHP等相比,由于其多线程运行而具有很高的执行效率.•由于Servlet/JSP默认是以多线程模式执行的,所以,在编写代码时需要非常细致地考虑多线程的同步问题.•如果在编写Servlet/JSP程序时不注意到多线程同步的问题,这往往造成编写的程序在少量用户访问时没有任何问题,而在并发用户上升到一定值时,就会经常出现一些莫明其妙的问题,对于这类随机性的问题调试难度也很大. Servlet的多线程同步问题: Servlet本身是单实例的,这样当有多个用户同时访问某

Servlet的模板方法和多线程

接触了一小段时间的servlet,下面就总结一下关于servlet的两个方面的知识,一个是模板方法的应用.另外一个是servlet多线程产生的原因. 1. 模板方法设计模式 定义一个操作中的算法的骨架,而将步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤. 2. Servlet中模板方法的应用 模板方法在servlet中的应用的类图 当客户端请求一个servlet的时候首先被调用的是service方法.Service方法就是定义骨架的方法,在service方

话说多线程

(十)话说多线程关键字: java 面试题 多线程 thread 线程池 synchronized 死锁作者:臧圩人(zangweiren) 发布时间:2008-08-08网址:http://zangweiren.javaeye.com>>>转载请注明出处!<<<线程或者说多线程,是我们处理多任务的强大工具.线程和进程是不同的,每个进程都是一个独立运行的程序,拥有自己的变量,且不同进程间的变量不能共享:而线程是运行在进程内部的,每个正在运行的进程至少有一个线程,而且不同

(2.1)servlet线程安全问题

本文参考链接:http://www.yesky.com/334/1951334.shtml 摘 要:介绍了Servlet多线程机制,通过一个实例并结合Java 的内存模型说明引起Servlet线程不安全的原因,给出了保证Servlet线程安全的三种解决方案,并说明三种方案在实际开发中的取舍. Servlet/JSP技术和ASP.PHP等相比,由于其多线程运行而具有很高的执行效率.由于Servlet/JSP默认是以多线程模式执行的,所 以,在编写代码时需要非常细致地考虑多线程的安全性问题.然而,很

并发并行多线程

Servlet多线程同步问题(important)最主要的原因之一是:Servlet是单例模式,一个Servlet给所有的用户提供服务,有可能造成资源混乱的模式 Servlet的多线程同步问题:Servlet本身是单实例的,这样当有多个用户同时访问某个Servlet时,会访问该唯一的Servlet实例中的成员变量,如果对成员变量进行写入操作,那就会导致Servlet的多线程问题,即数据不一致. 解决同步问题的方案:1.去除实例变量,使用局部变量(最好的)2.使用synchronized{} 1.

Servlet 是否线程安全 看完便知

摘 要:介绍了Servlet多线程机制,通过一个实例并结合Java 的内存模型说明引起Servlet线程不安全的原因,给出了保证Servlet线程安全的三种解决方案,并说明三种方案在实际开发中的取舍. 关键字:Servlet 线程安全 同步 Java内存模型 实例变量 Servlet/JSP技术和ASP.PHP等相比,由于其多线程运行而具有很高的执行效率.由于Servlet/JSP默认是以多线程模式执行的,所以,在编写代码时需要非常细致地考虑多线程的安全性问题.然而,很多人编写Servlet/J

servlet定义

servlet定义: Servlet是一个Java应用程序,运行在服务器端,用来处理客户端请求并作出响应的程序. Servlet多线程体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的. 当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类,此时它贮存于内存中..当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例.这样,当两个或多个线程同时访问同一个Serv

JavaWeb编程(八)servlet初级应用

1.MVC(model,view,controller) M:模型层(service(biz)\dao\javaBean) V:视图层(jsp,html) C:控制层(核心控制器)(Servlet)2.写一个servlet小服务程序步骤 2.1.创建一个web项目,然后新建一个servlet类(继承HttpServlet); 2.2.在web.xml中做servlet配置信息 <!-- servlet实例化信息 --> <servlet> <servlet-name>d

Servlet运行原理

一:servlet定义 Servlet是一个Java应用程序,运行在服务器端,用来处理客户端请求并作出响应的程序. (Servlet对象 在Servlet容器启动时被初始化,当第一次被请求时,Servlet容器将其实例化,此时它贮存于内存中. 如果存在多个请求,Servlet不会再被实例化,仍然由此Servlet将其进行处理,每一个请求都是一个线程,而不是进程,因此,Servlet对请求的处理的性能非常高) 对于Servlet,它被设计为多线程的(如果它是单线程的,你就可以想象,当1000个人同