Servlet的线程安全问题

来源:互联网 发布:java免费开源商城系统 编辑:程序博客网 时间:2024/05/16 04:41

一个web应用可能被来自四面八方的客户并发访问,而且有可能这些客户并发访问的是web应用中的同一个Servlet。Servlet容器为了保证能同时响应多个客户的要求访问同一个Servlet的HTTP请求,通常会为每一个请求分配一个工作线程,这些工作线程并发执行同一个Servlet对象的service方法,这就可能带来线程安全问题。

1. 第一种情况:利用Java的同步机制

因为Servlet也是一个Java类,所以Java的同步机制对于Servlet也管用。

2. 第二种情况:能作为service方法局部变量就不要作为Servlet的实例变量、尽量不对属性进行修改操作

在Java语言中,局部变量和实例变量有着不同的作用域,区别如下:

1. 局部变量在一个方法中定义。每当一个线程执行局部变量所在的方法时,在线程的堆栈中就会创建这个局部变量,当线程执行完该方法时,局部变量就结束生命周期。如果有多个线程同时执行该方法,那么每个线程都拥有自己的局部变量。

2. 实例变量在类中定义。类的每一个实例都拥有自己的实例变量,如果一个实例结束生命周期,那么属于它的实例变量也就结束生命周期。如果有多个线程同时执行一个实例的方法,而这个方法会访问一个实例变量,那么这些线程访问的是同一个实例变量。

所以可以作为Servlet局部变量的就不要作为实例变量,同时尽量不对Servlet的属性(实例变量)进行修改。

3. 第三种情况:实现javax.servlet.SingleThreadModel接口(标识接口),不鼓励使用此方法

javax.servlet.SingleThreadModel接口是一个被废弃的接口,该接口是为避免并发问题而提供的,如果一个Servlet实现了该接口,则Servlet容器实现可以采用以下两种方式之一来运行Servlet:

1. 在任意时刻,只允许有一个工作线程执行Servlet的service()方法。如果有多个客户同时请求访问该Servlet,那么这些客户请求被放入等待队列,容器会依次响应等待队列中的每个客户请求。这种实现方式实际上禁止了多个客户端对同一个Servlet的并发访问。

2. Servlet容器为每个Servlet创建一个对象池,在这个池中存放了同一个Servlet类的多个实例。如果有多个客户同时请求访问该Servlet,Servlet容器会为每个请求分配一个工作线程,并且从对象池中取出一个空闲的Servlet实例,把它分配给工作线程。每个工作线程执行自己的Servlet实例的service()方法。这种实现方式表面上允许客户端对同一个Servlet并发访问,但是实际上不同客户端访问的是同一个Servlet类的不同实例。

Tomcat采用第二种方式来提供对SingleThreadModel接口的支持。因为此种方式会为每个Servlet创建多个实例,对服务器的内存压力比较大,所以一般不推荐使用。









原创粉丝点击