`
haoran_10
  • 浏览: 436384 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java servlet拾遗(3)-servlet 线程安全问题

阅读更多
Servlet容器启动时,会对每一个Servlet对象实例化一次,而且是仅仅一次,在运行的时候,不管多少个请求都是同时执行这一个Servlet对象实例。也就是说Servlet对象是单实例多线程,这个时候,就需要注意到并发安全问题。
 
一、为什么不安全
    先看两个定义:
  • 实例变量:实例变量在类中定义。类的每一个实例都拥有自己的实例变量,如果多个线程同时访问该实例的方法,而该方法又使用到实例变量,那么这些线程同时访问的是同一个实例变量,会共享该实例变量。
  • 局部变量:局部变量在方法中定义。每当一个线程访问局部变量所在的方法时,在线程的堆栈中就会创建这个局部变量,线程执行完这个方法时,该局部变量就被销毁。所有多个线程同时访问该方法时,每个线程都有自己的局部变量,不会共享。
例如:
public class MyServlet extends HttpServlet{
 private static final long serialVersionUID = 1L;
 
 private String userName1 = null;//实例变量
 
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
         throws ServletException, IOException{
  userName1 = req.getParameter("userName1");
 
  String userName2 = req.getParameter("userName2");//局部变量
 
  //TODO 其他处理
 }
}
userName1则是共享变量,多个线程会同时访问该变量,是线程不安全的。
userName2是局部变量,不管多少个线程同时访问,都是线程安全的。
 
二、怎么解决
  • 如果不涉及到全局共享变量,全部放到局部变量,最好的做法
  • 如果使用到全局共享的场景,可以使用加锁的方式,比如
public class MyServlet extends HttpServlet{
 private static final long serialVersionUID = 1L;
 
 private String userName1 = null;//实例变量
 
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
         throws ServletException, IOException{
  synchronized (userName1) {
   userName1 = req.getParameter("userName1");
   //TODO
  }
 
 
  String userName2 = req.getParameter("userName2");//局部变量
 
  //TODO 其他处理
 }
}
或者使用线程安全的StringBuffer去代替String,
或者使用线程安全的容器比如:   java.util.concurrent.ConcurrentHashMap 等等
最好使用乐观锁的形式去加锁
 
0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics