概述 
在探讨java线程安全前,让我们先简要介绍一下Java语言。

任何语言,如C++,C#,Java,它们都有相通之处,特别是语法,但如果有人问你,Java语言的核心是什么?类库?关键字?语法?似乎都不 是。Java语言的核心,也就是Sun始终不愿意开源的东西:Java虚拟机的实现(不过sun公开了其Java虚拟机规范),也就有了BEA的 JRockit,IBM的Jikes,Sun的Hotspot。

Java的核心有两点,Java类加载(Java Class Loader)和Java内存管理,它们具体体现在Java类库的以下几个类:

java.lang.ClassLoader(java.lang.Class):我们调用的类,包括其接口和超类,import的类是怎么被Java虚拟机载入的?为什么static的字段在servlet容器里面可以一直生存下去(Spring容器中)?

java.lang.Thread(java.lang.ThreadLocal):垃圾回收是怎么进行的(垃圾回收线程)?我们的程序是怎么退出的? 

java.lang.refelect.Proxy(java.lang.refelect.Method):为什么Tomcat、 Tapestry、Webwork、Spring等容器和框架可以通过配置文件来调用我们写的类?Servlet规范、JSF规范、EJB规范、JDBC 规范究竟是怎么回事?为什么它们几乎都是一些接口,而不是具体类?

Servlet线程安全

在Java的server side开发过程中,线程安全(Thread Safe)是一个尤为突出的问题。因为容器,如Servlet、EJB等一般都是多线程运行的。虽然在开发过程中,我们一般不考虑这些问题,但诊断问题 (Robust),程序优化(Performance),我们必须深入它们。

什么是线程安全?

在Java里,线程安全一般体现在两个方面: 

  1、多个thread对同一个java实例的访问(read和modify)不会相互干扰,它主要体现在关键字synchronized。如 ArrayList和Vector,HashMap和Hashtable(后者每个方法前都有synchronized关键字)。如果你在 interator一个List对象时,其它线程remove一个element,问题就出现了。 

  2、每个线程都有自己的字段,而不会在多个线程之间共享。它主要体现在java.lang.ThreadLocal类,而没有Java关键字支持,如像static、transient那样。 

一个普遍的疑问,我们的Servlet中能够像JavaBean那样declare instance或static字段吗?如果不可以?会引发什么问题?

答案是:不可以。下面以实例讲解:

首先,写一个普通的Servlet,里面有instance字段count:

web.xml  >>

<servlet><servlet-name>SimpleServlet</servlet-name><servlet-class>servlet.SimpleServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>SimpleServlet</servlet-name><url-pattern>/SimpleServlet</url-pattern>
</servlet-mapping>

SimpleServlet  >>

 public class SimpleServlet extendsHttpServlet {private int counter = 0;  @Overrideprotected voidservice(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {response.getWriter().println("<HTML><BODY>");response.getWriter().println(this + " ==> ");response.getWriter().println(Thread.currentThread()+ ": <br>");for(int c=0;c<10;c++){response.getWriter().println("Counter = " + counter + "");try{Thread.sleep(1000);  counter++;  }catch(Exception e) {e.printStackTrace();}}response.getWriter().println("</BODY></HTML>");}}

  test.html  >>

<html>  <body>  <table>  <tr>  <td><iframesrc="SimpleServlet"name="servlet1"height="200%"> </iframe></td>  </tr>  </table>  </body>
</html> 

  test.html的内容如上所示,打开3个IE浏览器,同时在浏览器中输入:

  
  a: http://localhost:8080/ServletTest/SimpleServlet    b: http://localhost:8080/ServletTest/SimpleServlet    c: http://localhost:8080/ServletTest/SimpleServlet 

  测试结果如下:

  我们会发现三点:

  1、Servlet是一个单例对象(Singleton),因为我们看到多次请求的this指针所有打印出来的hashCode值都相同。
  2、servlet在不同的线程(线程池)中运行,如http-8080-1,http-8080-2,http-8080-3 等输出值可以明显区分出不同的线程执行了不同一段Servlet逻辑代码。
  3、count变量在不同的线程中共享,而且它的值被不同的线程修改,输出时已经不是顺序输出。也就是说,其他的线程会篡改当前线程中实例变量的值,针对这些对象的访问不是线程安全的。

  上面的结果,违反了线程安全的两个方面。

  那么,我们怎样保证按照我们期望的结果运行呢?首先,我想保证产生的count都是顺序执行的。 
  我们将Servlet代码重构如下:

  

public class SimpleServlet extendsHttpServlet {private int counter = 0;private String mutex = ""; @Overrideprotected voidservice(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {response.getWriter().println("<HTML><BODY>");response.getWriter().println(this + " ==> ");response.getWriter().println(Thread.currentThread()+ ": <br>");synchronized(mutex){for(int c=0;c<10;c++){response.getWriter().println("Counter = " + counter + "<BR>");try{Thread.sleep(1000);  counter++;  }catch(Exception e) {e.printStackTrace();}}}response.getWriter().println("</BODY></HTML>");}}

  这符合要求,输出都是按顺序的,这正式synchronized的含义。

  附带说一下,我现在synchronized的是一个字符串变量mutex,不是this对象,这主要是从performance和 Scalability考虑。Synchronized用在this对象上,会带来严重的可伸缩性的问题(Scalability),所有的并发请求都要排队!

转载:http://www.cnblogs.com/gw811/archive/2012/09/07/2675294.html

转载于:https://www.cnblogs.com/go-skill/p/6078082.html

Servlet线程安全相关推荐

  1. 深入研究Servlet线程安全性问题

    摘 要:介绍了Servlet多线程机制,通过一个实例并结合Java 的内存模型说明引起Servlet线程不安全的原因,给出了保证Servlet线程安全的三种解决方案,并说明三种方案在实际开发中的取舍. ...

  2. Servlet功能实现和执行过程、servlet的生命周期、Servlet线程安全问题、Servlet的三种映射方式、ServletConfig、ServletContext

    1. 什么是Servlet? Servlet是SUN公司提供的一套规范,名称就叫Servlet规范,它也是JavaEE规范之一. 第一:Servlet是一个运行在web服务端的java小程序 第二:它 ...

  3. Servlet线程安全2

    为什么80%的码农都做不了架构师?>>>    Servlet的多线程机制 Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的.当客户端第一次请 ...

  4. IT兄弟连 JavaWeb教程 Servlet线程安全问题

    2019独角兽企业重金招聘Python工程师标准>>> 在Internet中,一个Web应用可能被来自西面八方的客户并发访问(即同时访问),而且有可能这些客户并发访问的是Web应用中 ...

  5. tomcat servlet 线程

    在服务器里,有一个servlet,当客户端第一次访问服务器时,tomcat会 帮我们建一个servlet的对象出来,(注意: tomcat里面可能部署了10个Servlet,如果某一个Servlet从 ...

  6. java servlet 多线程_Servlet的多线程和线程安全

    线程安全 首先说明一下对线程安全的讨论,哪种情况我们可以称作线程安全? 网上对线程安全有很多描述,我比较喜欢<Java并发编程实战>给出的定义,"当多个线程访问某个类时,不管运行 ...

  7. servlet单实例多线程 ---线程安全问题是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。(所有建议不要在servlet中定义成员变

    Servlet 单例多线程 Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servl ...

  8. javaweb学习总结二十三(servlet开发之线程安全问题)

    一:servlet线程安全问题发生的条件 如果多个客户端访问同一个servlet时,发生线程安全问题,那么它们访问的是相同的资源.如果访问 的不是相同资源,则不存在线程安全问题. 实例1:不会产生线程 ...

  9. 关于java Servlet,Struts,springMVC 的线程安全问题

    2019独角兽企业重金招聘Python工程师标准>>> 现在主流的java的前端框架有:struts1,struts2,springmvc 还有最根本的servlet; 前些天一个朋 ...

最新文章

  1. Java源码详解四:String源码分析--openjdk java 11源码
  2. JavaScript使用技巧精萃
  3. python 引用(import)文件夹下的py文件的方法
  4. 【HoorayOS】开源的Web桌面应用框架(第二版 v120311)
  5. 上传文件Base64格式(React)
  6. 【证明】【一题多解】【等价转换】—— 排列组合的计算
  7. 下行文格式图片_通知的格式及范文图片_通知格式 通知的格式及范文
  8. 全国各省份简称、省会、经纬度
  9. 自然语言处理的会议、论文集下载
  10. 【classic】MMD镜头+动作打包下载.zip
  11. 2.1 Apache Hadoop、HDFS - Apache Hadoop概述
  12. FDD LTE B1是什么
  13. 小白通过JDBC在AndroidStudio一步步来访问MYSQL数据库
  14. python大一期末考试_python期末考试复习试卷
  15. 微信公众号文章链接正则校验
  16. Ctrl+win+d win的虚拟桌面如何撤销
  17. linux ide sata硬盘,Linux 下SATA与IDE硬盘区别
  18. 最全的 cadence 元器件库详细说明
  19. 最新虚拟商品自动发货系统源码 v1.1.1 (发货100)
  20. 计算机老师副业能做什么,教师除了本职工作,还能做哪些副业?

热门文章

  1. k8s StatefulSet
  2. JVM调优:jdk1.8的所有-X参数
  3. Python Django 图片上传及显示代码示例
  4. 请简短说明一下你对AQS的理解
  5. springmvc配置文件的主要内容
  6. jQuery EasyUI 选项卡面板tabs使用实例精讲
  7. MQTT连接阿里云IoT(四)
  8. C++的拷贝构造函数、operator=运算符重载,深拷贝和浅拷贝、explicit关键字
  9. VC6.0显示代码行号
  10. ArrayList集合的使用和源码详细分析