讲servlet之前要先讲一下servlet容器,
Servlet容器是web server或application server的一部分,供基于请求/响应发送模型的网络服务,解码基
于 MIME 的请求,并且格式化基于 MIME 的响应。Servlet 容器也包含并管理 Servlet 生命周期。
所以对于servlet的线程模型和它所依赖的容器有关系。
tomcat是最常用的servlet容器。
Tomcat介绍
Tomcat是Apache基金会下的一个开源项目。。。。。。。。。。
实现了对Servlet和JSP的支持,并提供了作为Web服务器的一些特有功能
Tomcat提供了一个Jasper编译器用以将JSP编译成对应的Servlet。
(上面都是废话)
Tomcat的处理过程
Tomcat对servlet的处理的过程是:
- 客户端第一次请求Servlet的时候,tomcat会根据web.xml配置文件实例化servlet
- 当又有一个客户端访问该servlet的时候,不会再实例化该servlet
tomcat自己维护了一个线程池,在收到请求时,会到池子里找可用的线程。如果找不到可用的线程,并且线程池已经到了最大线程数,那么请求就会放到一个队列中等待获取可用的线程。
举个栗子:
创建一个Servlet,每次去请求都打印出来自己的hashcode
public class MyServlet extends HttpServlet{
private Logger logger = Logger.getLogger(this.getClass());
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
logger.debug(this.hashCode());
}
}
结果是这样的:
会发现每次请求的servlet都是同一个,也就是每个servlet只有一个实例。
所以servlet是线程不安全的,如果使用静态或者实例变量中存储请求和响应对象,那么在多线程去情况下一定会出现问题。
设计线程安全的Servlet
实现SingleThreadModel接口
SingleThreadModel接口是一个标识接口,如果实现了这个接口,那么Tomcat就会保证一个时刻只有一个线程对这个servlet进行操作,其他的线程排着队慢慢来。
这种方式虽然安全,但是太低效了。
因此Servlet的规范中已经被废弃了。
使用同步的类
对集合进行操作的时候,选则同步的集合就不会有线程不安全的问题了
Synchronized关键字
多个servlet对外部对象进行操作,一定要上锁,这种锁机制效率也很慢。
使用局部变量
变量都是局部变量,用完就回收了,再用再创建。
属性的线程安全
ServletContext是线程不安全的,多线程下可以同时进行读写,因此我们要对其读写操作进行同步或者深度的clone。
HttpSession是线程不安全的,和ServletContext的操作一样。