




已阅读5页,还剩4页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
J2EE的线程安全ThreadLocal1.在用Servlet时,我们都知道Servlet只会被初始化一次,只有一个实例。2.在Struts1中,ActionServlet也仅是初始化一次,也是单实例。为什么会这样,无非是为了提高效率。但是线程安全不容忽视。但是在WebWork、Struts2却做好了线程安全。下面具体介绍:Servlet线程安全概述在探讨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),我们必须深入它们。什么是线程安全?Thread-safe describes a program portion or routine that can be called from multiple programming threads without unwanted interaction between the threads。在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:Java代码 1 public class SimpleServlet extends HttpServlet 2 / A variable that is NOT thread-safe! 3 private int counter = 0; 4 5 public void doGet(HttpServletRequest req, HttpServletResponse resp) 6 throws ServletException, IOException 7 doPost(req, resp); 8 9 10 public void doPost(HttpServletRequest req, HttpServletResponse resp) 11 throws ServletException, IOException 12 resp.getWriter().println(); 13 resp.getWriter().println(this + = ); 14 resp.getWriter().println(Thread.currentThread() + : ); 15 16 for (int c = 0; c 10; c+) 17 resp.getWriter().println(Counter = + counter + ); 18 try 19 Thread.sleep(long) Math.random() * 1000); 20 counter+; 21 catch (InterruptedException exc) 22 23 24 resp.getWriter().println(); 25 26 然后,我们通过一个html页面向该servlet发出三次请求:Html代码 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 刷新页面几次后,产生的结果为:Java代码 47 com.zwchen.servlet.SimpleServlet11e1bbf = Threadhttp-8081-Processor23,5,main: 48 Counter = 60 49 Counter = 61 50 Counter = 62 51 Counter = 65 52 Counter = 68 53 Counter = 71 54 Counter = 74 55 Counter = 77 56 Counter = 80 57 Counter = 83 58 59 com.zwchen.servlet.SimpleServlet11e1bbf = Threadhttp-8081-Processor22,5,main: 60 Counter = 61 61 Counter = 63 62 Counter = 66 63 Counter = 69 64 Counter = 72 65 Counter = 75 66 Counter = 78 67 Counter = 81 68 Counter = 84 69 Counter = 87 70 71 com.zwchen.servlet.SimpleServlet11e1bbf = Threadhttp-8081-Processor24,5,main: 72 Counter = 61 73 Counter = 64 74 Counter = 67 75 Counter = 70 76 Counter = 73 77 Counter = 76 78 Counter = 79 79 Counter = 82 80 Counter = 85 81 Counter = 88 我们会发现三点:servlet只产生了一个Servlet对象,因为输出this时,其hashcode都一样,servlet在不同的线程(线程池)中运行,如http-8081-Processor22,http-8081-Processor23Count被这三个doGet方法共享,并且并行修改。上面的结果,违反了线程安全的两个方面。那么,我们怎样保证按照我们期望的结果运行呢?首先,我想保证产生的count都是顺序执行的。我们将Servlet代码重构如下:Java代码 82 public class SimpleServlet extends HttpServlet 83 / A variable that is NOT thread-safe! 84 private int counter = 0; 85 private String mutex = ; 86 87 public void doGet(HttpServletRequest req, HttpServletResponse resp) 88 throws ServletException, IOException 89 doPost(req, resp); 90 91 92 public void doPost(HttpServletRequest req, HttpServletResponse resp) 93 throws ServletException, IOException 94 resp.getWriter().println(); 95 resp.getWriter().println(this + : ); 96 synchronized (mutex) 97 for (int c = 0; c 10; c+) 98 resp.getWriter().println(Counter = + counter + ); 99 try 100 Thread.sleep(long) Math.random() * 1000); 101 counter+; 102 103 catch (InterruptedException exc) 104 105 106 107 resp.getWriter().println(); 108 109 我们的输出结果为:Java代码 110 com.zwchen.servlet.SimpleServlet109da93: 111 Counter = 0 112 Counter = 1 113 Counter = 2 114 Counter = 3 115 Counter = 4 116 Counter = 5 117 Counter = 6 118 Counter = 7 119 Counter = 8 120 Counter = 9 121 122 com.zwchen.servlet.SimpleServlet109da93: 123 Counter = 10 124 Counter = 11 125 Counter = 12 126 Counter = 13 127 Counter = 14 128 Counter = 15 129 Counter = 16 130 Counter = 17 131 Counter = 18 132 Counter = 19 133 134 com.zwchen.servlet.SimpleServlet109da93: 135 Counter = 20 136 Counter = 21 137 Counter = 22 138 Counter = 23 139 Counter = 24 140 Counter = 25 141 Counter = 26 142 Counter = 27 143 Counter = 28 144 Counter = 29 这符合了我们的要求,输出都是按顺序的,这正式synchronized的含义。附带说一下,我现在synchronized的是一个字符串变量mutex,不是this对象,这主要是从performance和Scalability考虑。Synchronized用在this对象上,会带来严重的可伸缩性的问题(Scalability),所有的并发请求都要排队!现在,我们保证了顺序,但是我们怎么保证Counter字段(不是局部变量!)在每个Servlet的线程下都是独立的呢?也就是说,并发请求时,它们都不相互干扰。我现在将Servlet代码重构如下:Java代码 145 public class SimpleServlet extends HttpServlet 146 private ThreadLocal counter = new ThreadLocal() 147 protected synchronized Object initialValue() 148 return new Integer(0); 149 150 ; 151 152 public void doGet(HttpServletRequest req, HttpServletResponse resp) 153 throws ServletException, IOException 154 doPost(req, resp); 155 156 157 public void doPost(HttpServletRequest req, HttpServletResponse resp) 158 throws ServletException, IOException 159 resp.getWriter().println(); 160 resp.getWriter().println( 161 this + + Thread.currentThread() + : ); 162 for (int c = 0; c 10; c+) 163 resp.getWriter().println(counter.get() + ); 164 try 165 Thread.sleep(long) Math.random() * 1000); 166 int c1 = (Integer) counter.get().intValue(); 167 c1+; 168 counter.set(new Integer(c1); 169 catch (InterruptedException exc) 170 171 172 173 resp.getWriter().println(); 174 175 现在,我刷新html页面三次,第三次结果如下:Java代码 176 com.zwchen.servlet.SimpleServlet124e935Threadhttp-8081-Processor22,5,main: 177 20 178 21 179 22 180 23 181 24 182 25 183 26 184 27 185 28 186 29 187 188 com.zwchen.servlet.SimpleServlet124e935Threadhttp-8081-Processor25,5,main: 189 20 190 21 191 22 192 23 193 24 194 25 195 26 196 27 197 28 198 29 199 200 com.zwchen.servlet.SimpleServlet124e935Threadhttp-8081-Processor23,5,main: 201 20 202 21 203 22 204 23 205 24 206 25 207 26 208 27 209 28 210 29 从以上结果,我们可以发现:1、在该html页面内的并发三次请求中,该Servlet里面的counter字段都不相互干扰2、counter字段还是实例字段,并且都会保留状态,不是每次都用0开始3、html页面内的三次请求都在不同的线程,但在同一个实例中。总之,在Java里面,字段(不是局部变量)有三个共享范围:instance field,static field,local thread field,而后者往往在服务器端这种多线程环境必须考虑到的。 在J2EE项目开发过程中,ThreadLocal类有时有非常重要的作用,下面是我碰到的,但可以延伸:1、在用Hibernate做web开发的持久化时,有个模式叫做Open Session In View,也就是将session保留到页面中,在response结束后,在OpenSessionInViewFilter中关闭session,这对于延迟加载非常有效,例如,我们在页面上显示User的详细信息,需要显示该user的所属De
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 回归测试意义分析试题及答案
- 公路工程招标流程试题及答案
- 互联网协议解析试题及答案
- 2025年信息管理师能力提升试题及答案
- 测试工具在项目中的应用实例试题及答案
- 行政管理与公共政策整合试题及答案
- 行政理论知识点回顾试题及答案
- 基于数字化档案的幼儿成长综合评估方法探讨
- 民间故事讲述馆行业深度调研及发展项目商业计划书
- 木材雕塑创作AI应用企业制定与实施新质生产力项目商业计划书
- Unit2Lesson3GettingToTheTop课件-高中英语北师大版(2019)选择性必修第一册
- 卡通风青春毕业季PPT模板课件
- 《804泄爆墙安装施工方案》
- 环境及理化因素损伤救护
- 心电监护课件精品PPT课件
- 大气污染控制工程课程设计---电除尘器设计说明书
- 上公司人力资源管理制度非常全面
- 上泰pH计SUNTEX-PC-3110操作说明书
- 专业大户、家庭农场情况调查表
- summer-vibe-的中英歌词
- 小学英语正在进行时用法及习题(含答案)
评论
0/150
提交评论