5、Servlet 的多线程问题
我们通过 Servlet 的生命周期可以知道,Servlet 类的构造器只会在第一次访问的时候调用,后面的请求都不会再重新创建 Servlet 实例。即 Servlet 是单例,那么既然是单例的,那就要注意多线程访问所造成的安全问题。如下:
package com.ys.servlet;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class HelloServlet extends GenericServlet{
//多线程共享资源
private int i = 0;
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
i ;
//为了使多线程访问安全问题更加突出,我们增加一个延时程序
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
我们用两个浏览器,输入 http://localhost:8080/ServletImprove/hello,然后一起访问,不断刷新,结果如下:
结果分析:显然,我们用两个浏览器访问,便相当于两个线程,第一个访问,已经执行了 i ,但是还没来得及打印 i 的值,就马上就睡眠了;接着第二个浏览也来访问,执行 i ,那么i的值相当于增加加了两次1,然后这两个浏览器输出最终结果。这便造成了多线程访问共享资源造成冲突。那么如何解决多线程冲突呢?
可以参考这篇文章:如何解决多线程同步问题 http://www.cnblogs.com/ysocean/p/6883729.html
那么在 Servlet 中如何处理呢?
第一种方法:使用同步代码块
package com.ys.servlet;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class HelloServlet extends GenericServlet{
//多线程共享资源
private int i = 0;
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
synchronized (this) {
i ;
//为了使多线程访问安全问题更加突出,我们增加一个延时程序
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}
结果:
分析:这种办法虽然能解决多线程同步问题,但是如果 延时程序特别长,那么会造成访问假死的现象。即第一个线程访问结果没有出来,第二个线程就会一直卡死,出不来结果
第二种办法:实现接口 SingleThreadModel
package com.ys.servlet;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.SingleThreadModel;
public class HelloServlet extends GenericServlet implements SingleThreadModel{
//多线程共享资源
private int i = 0;
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
i ;
//为了使多线程访问安全问题更加突出,我们增加一个延时程序
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
结果: