1、Servlet 单例多线程
既然java很多都是多并发的场景,那么为什么Servlet还要设计成单例模式呢!
①:Servlet单实例,减少了产生servlet的开销;
②:通过线程池来响应多个请求,提高了请求的响应时间;
③:Servlet容器并不关心到达的Servlet请求访问的是否是同一个Servlet还是另一个Servlet,直接分配给它一个新的线程;如果是同一个Servlet的多个请求,那么Servlet的service方法将在多线程中并发的执行;
2、那么如何去保证在多用户访问时它的线程安全?
1、实现 SingleThreadModel 接口(已经被废除了)
该接口指定了系统如何处理对同一个Servlet的调用。如果一个Servlet被这个接口指定,那么在
这个Servlet中的service方法在某一时刻只有一个线程会执行。
2、同步对共享数据的操作:
使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段,
但是呢注意不要给整个方法去加sychronized关键字,这样导致了虽然线程安全了,但效率确太
低,因此我们在使用synchronized的时候,只需要对小范围的代码块进行加锁,就可以了,这样即
实现了线程安全,也不会使得程序的性能太低;
3、尽量避免使用实例变量:
数据安全就是由于多个线程或者操作是对同一个数据进行操作,因此Servlet中我们尽量少去使
用实例的变量,以及一些静态的属性,这样会使得发生数据安全的概率大大增加;我们可以通过多
使用局部变量;
@WebServlet("/test")
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public TestServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String sname = request.getParameter("sname");
ServletContext servletContext = getServletContext();
Object obj = new Object();
//通过给Servlet容器添加一个外部属性
servletContext.setAttribute("obj",obj);
//再通过getAttribute(String name)去获取相应的值
//这种给ServletContext设置的属性,那么所有的Servlet实例对象都能访问或者操作到它,
//如果多用户访问时,就会造成线程安全的问题,因此这里我们需要去进行加锁处理,来保证线程安全
Object obj2 = servletContext.getAttribute("obj");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
4、当我们需要使用到集合时,尽量选择线程安全的集合来进行操作。如
CurrentHashMap,CopyOnWriteArrayList等