﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-正如水云的心情，一览飘渺的天空</title><link>http://www.blogjava.net/yeping573/</link><description /><language>zh-cn</language><lastBuildDate>Mon, 27 Apr 2026 16:09:29 GMT</lastBuildDate><pubDate>Mon, 27 Apr 2026 16:09:29 GMT</pubDate><ttl>60</ttl><item><title>关于多线程的问题  高手指点</title><link>http://www.blogjava.net/yeping573/archive/2009/04/24/267361.html</link><dc:creator>王业平</dc:creator><author>王业平</author><pubDate>Fri, 24 Apr 2009 07:04:00 GMT</pubDate><guid>http://www.blogjava.net/yeping573/archive/2009/04/24/267361.html</guid><wfw:comment>http://www.blogjava.net/yeping573/comments/267361.html</wfw:comment><comments>http://www.blogjava.net/yeping573/archive/2009/04/24/267361.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/yeping573/comments/commentRss/267361.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yeping573/services/trackbacks/267361.html</trackback:ping><description><![CDATA[<p><span style="font-family: Comic Sans MS"><span style="color: red"><strong>此时程序中最多有几个存活的线程，个人认为应该是4个，怎么就是看不到是4个的结果呢？<br />
</strong></span><span style="color: #008000">package Test;</span></span></p>
<p><span style="font-family: Comic Sans MS"><span style="color: #008000">public class Testthread{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public static void main(String[] args){</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//测定当前活动的线程数目 肯定有一个<span style="color: #0000ff"><strong>主线程</strong></span>在运行<br />
<span style="color: #339966"><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("=========header========"+Thread.activeCount());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadTest tt=new ThreadTest();&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RunTest rt=new RunTest(); </span></span><strong><span style="color: #0000ff"><strong>//在下面新建线程里被启动</strong></span><br />
</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">new Thread(<span style="color: #ff0000">rt</span>).start();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="color: #0000ff">//新建立的一个线程 启动</strong></span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">tt.start();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>//已经建立的线程&nbsp;启动</strong></span><br />
<span style="color: #808000">&nbsp;<span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("===========footer======"+Thread.activeCount());<br />
&nbsp;}<br />
}<br />
class ThreadTest extends Thread{<br />
&nbsp;public void run(){<br />
&nbsp;&nbsp;System.out.println("==========I'm over thread=========");<br />
&nbsp;}<br />
}</span><br />
<span style="color: #008000">class RunTest implements Runnable{<br />
&nbsp;public void run(){<br />
&nbsp;&nbsp;System.out.println("==========I'm over runnable==========");<br />
&nbsp;}<br />
}</span></span><br />
<br />
<span style="color: #ff0000"><span style="font-family: Comic Sans MS">打印结果：<br />
第一类结果 （次序有时不同）<br />
</span><span style="font-family: Comic Sans MS">=========header========1<br />
===========footer======3<br />
==========I'm over thread=========<br />
==========I'm over runnable==========<br />
<br />
第二类结果<br />
=========header========1<br />
==========I'm over runnable==========<br />
===========footer======2<br />
==========I'm over thread=========</span></span></span><span style="font-family: Comic Sans MS"><br />
<br />
</p>
</span>
<img src ="http://www.blogjava.net/yeping573/aggbug/267361.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yeping573/" target="_blank">王业平</a> 2009-04-24 15:04 <a href="http://www.blogjava.net/yeping573/archive/2009/04/24/267361.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>servlet 生命周期 即工作流程</title><link>http://www.blogjava.net/yeping573/archive/2009/04/24/267289.html</link><dc:creator>王业平</dc:creator><author>王业平</author><pubDate>Fri, 24 Apr 2009 02:13:00 GMT</pubDate><guid>http://www.blogjava.net/yeping573/archive/2009/04/24/267289.html</guid><wfw:comment>http://www.blogjava.net/yeping573/comments/267289.html</wfw:comment><comments>http://www.blogjava.net/yeping573/archive/2009/04/24/267289.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/yeping573/comments/commentRss/267289.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yeping573/services/trackbacks/267289.html</trackback:ping><description><![CDATA[<span style="color: #800000; font-family: 楷体_GB2312"><strong>Servlet的生命周期：<br />
<br />
（1）装载Servlet。这项操作一般是动态执行的。然而，Server通常会提供一个管理的选项，用于在Server启动时强制装载和初始化特定的Servlet；<br />
<br />
（2）Server创建一个Servlet的实例；<br />
<br />
（3）Server调用Servlet的init()方法；<br />
<br />
（4）一个客户端的请求到达Server；<br />
<br />
（5）Server创建一个请求对象；<br />
<br />
（6）Server创建一个响应对象；<br />
<br />
（7）Server激活Servlet的service()方法，传递请求和响应对象作为参数；<br />
<br />
（8）service()方法获得关于请求对象的信息，处理请求，访问其他资源，获得需要的信息；<br />
<br />
（10）service()方法使用响应对象的方法，将响应传回Server、最终到达客户端。<br />
<br />
service()方法可能激活其它方法以处理请求，如doGet()或doPost()或程序员自己开发的新的方法；<br />
<br />
对于更多的客户端请求，Server创建新的请求和响应对象，仍然激活此Servlet的service()方法，将这两个对象作为参数传递给它。如此重复以上的循环，但无需再次调用init()方法。一般Servlet只初始化一次；<br />
<br />
当Server不再需要Servlet时，Server调用Servlet的Destroy()方法。<br />
</strong></span>
<img src ="http://www.blogjava.net/yeping573/aggbug/267289.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yeping573/" target="_blank">王业平</a> 2009-04-24 10:13 <a href="http://www.blogjava.net/yeping573/archive/2009/04/24/267289.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转帖 servlet的线程安全问题</title><link>http://www.blogjava.net/yeping573/archive/2009/04/23/267180.html</link><dc:creator>王业平</dc:creator><author>王业平</author><pubDate>Thu, 23 Apr 2009 08:31:00 GMT</pubDate><guid>http://www.blogjava.net/yeping573/archive/2009/04/23/267180.html</guid><wfw:comment>http://www.blogjava.net/yeping573/comments/267180.html</wfw:comment><comments>http://www.blogjava.net/yeping573/archive/2009/04/23/267180.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yeping573/comments/commentRss/267180.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yeping573/services/trackbacks/267180.html</trackback:ping><description><![CDATA[<span style="font-family: 楷体_GB2312">不知如何转帖，只有ctrl +v了<br />
</span>
<h4 class="c_tx"><span style="font-family: 楷体_GB2312">Servlet线程安全探讨</span></h4>
<div class="art_info c_tx2"><span style="font-family: 楷体_GB2312"><span class="right">阅读(<span class="hit" id="viewCount3">67</span>) <span class="spl">评论(<span class="hit" id="commentCount3">0</span>)</span></span> 发表时间：2008年11月20日 15:46 </span>
<p><span style="font-family: 楷体_GB2312">本文地址：</span><a style="cursor: pointer" onclick="copyBlogURL();return false;" href="javascript:;"><span style="font-family: 楷体_GB2312">http://qzone.qq.com/blog/190658200-1227167200 </span></a></p>
<div class="tags bor2"><span style="font-family: 楷体_GB2312">本文标签: </span><a href="http://qzone.soso.com/qz.q?sc=qz&amp;ch=s.qz.diary&amp;ty=diary&amp;w=%53%65%72%76%6c%65%74&amp;cid=qz.s.tag" target="_blank"><span style="font-family: 楷体_GB2312">Servlet</span></a><span style="font-family: 楷体_GB2312">&nbsp;</span><a href="http://qzone.soso.com/qz.q?sc=qz&amp;ch=s.qz.diary&amp;ty=diary&amp;w=%cf%df%b3%cc%b0%b2%c8%ab&amp;cid=qz.s.tag" target="_blank"><span style="font-family: 楷体_GB2312">线程安全</span></a></div>
<div id="quoteinfo" style="margin-bottom: 10px"></div>
<div id="voteAnchor"></div>
</div>
<!--文章内容开始-->
<div class="real_blog" id="veryContent" style="text-indent: 2em; line-height: 26px; height: auto! important">
<table id="blogContentTable" style="table-layout: fixed; width: 100%; position: relative" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" valign="top">
            <div id="blogContainer"><span style="font-family: 楷体_GB2312"><img id="paperPicArea0" style="display: none" height="1" alt="" src="http://qzone.qq.com/ac/b.gif" width="1" /> </span>
            <div id="paperTitleArea" align="center"></div>
            <span style="font-family: 楷体_GB2312"><img id="paperPicArea" style="display: none" height="1" alt="" src="http://qzone.qq.com/ac/b.gif" width="1" /> </span>
            <div id="blogDetailDiv" style="font-size: 16px"><span style="font-family: 楷体_GB2312">我们在开发<font style="line-height: 1.5em" size="3">JAVA WEB</font><wbr>应用程序，大多都会考虑用<font style="line-height: 1.5em" size="3">MVC</font><wbr>模式的框架来部署（相信没有程序员再考虑前两者简单的模式了吧。），这也是基于下面的原因：<br />
            <font style="line-height: 1.5em" size="3">一、MVC</font><wbr>由于分层清晰，容易看到整个系统流程的架构，对于越来越复杂的系统是有相当大的帮助。<br />
            <font style="line-height: 1.5em" size="3">二、 </font><wbr>扩展性，耦合性低。各层影响相当少，如<font style="line-height: 1.5em" size="3">JSP</font><wbr>页面只负责数据显示，<font style="line-height: 1.5em" size="3">M</font><wbr>负责业务逻辑处理，<font style="line-height: 1.5em" size="3">C</font><wbr>相当于<font style="line-height: 1.5em" size="3">Servlet</font><wbr>来控制流程的转向。等等这一系列的好处。<br />
            <span style="color: red"><strong>用<font style="line-height: 1.5em" size="3">MVC</font><wbr>的模式，其本质就是用<font style="line-height: 1.5em" size="3">Servlet</font><wbr>的应用技术</strong></span>。<font style="line-height: 1.5em" size="3">Servlet/jsp</font><wbr>和其他如<font style="line-height: 1.5em" size="3">ASP\PHP</font><wbr>语言相比，由于使用了多线程运行技术与具有很高的执行效率。但是也就是<font style="line-height: 1.5em" size="3">Servlet</font><wbr>由于默认多线程模式执行，依我们所了解线程安全性问题，也就不得不要考虑在<font style="line-height: 1.5em" size="3">Servlet</font><wbr>中也存在这样的问题，然而，很多程序员只专注于业务逻辑的处理，并没有注意到多线程的安全性的问题（在此编写之前，我也存在这样的经历，不过还好。。。。），这往往造成编写的程序在用户量少的时候没出什么问题，而一旦发现大量的并发用户时，而且这数量达到一定的数量时，就会出现一系列莫名的问题，这问题在下面我们可以看的到。<br />
            <strong style="color: red"><font style="line-height: 1.5em" size="3">Servlet</font><wbr></strong><wbr>的多线程机制</strong>是怎么样的呢：</strong><wbr><br />
            <font style="line-height: 1.5em" size="3">Servlet</font><wbr>体系结构是建立在<font style="line-height: 1.5em" size="3">JAVA</font><wbr>的多线程机制上的，但它的生命周期是由<font style="line-height: 1.5em" size="3">WEB</font><wbr>容器来管理的，当客户端第一次请求某个<font style="line-height: 1.5em" size="3">Servlet</font><wbr>时，<font style="line-height: 1.5em" size="3">Servlet</font><wbr>容器会根据<font style="line-height: 1.5em" size="3">web.xml</font><wbr>的配置实例化相应的<font style="line-height: 1.5em" size="3">Servlet</font><wbr>类，当有新的客户端来请求这个<font style="line-height: 1.5em" size="3">Servlet</font><wbr>时，容器一般不会再实例化这个<font style="line-height: 1.5em" size="3">Servlet</font><wbr>类，而是以线程方式去调用这个实例的方法，然后再有更多的客户端来请求时，就存在了多个线程在使用这个实例。并且<strong style="color: #008000"><font style="line-height: 1.5em" size="3">Servlet</font><wbr>容器会自动使用线程池技术来支持系统的运行。<br />
            </strong>在这样的情况，当两个或者多个客户端同时请求同一<font style="line-height: 1.5em" size="3">Serlvet</font><wbr>时，就会存在多个线程同时访问同一资源的情况，数据就可能变的不一致，所以在用<font style="line-height: 1.5em" size="3">Servlet</font><wbr>搭建<font style="line-height: 1.5em" size="3">WEB</font><wbr>应用程序时如果不考虑线程的问题，就会出现难以发现的问题。<br />
            <font style="line-height: 1.5em" size="3">Servlet</font><wbr></strong><wbr>线程安全问题的例子：</strong><wbr><br />
            <font style="line-height: 1.5em" size="3">Servlet</font><wbr>线程是由于使用实例变量不当而导致的，这里有如下的例子：<br />
            代码程序如下：<br />
            <wbr><span style="font-family: Comic Sans MS">public<wbr style="font-family: "> <wbr style="font-family: ">class<wbr style="font-family: "> SecurityTest <wbr style="font-family: ">extends<wbr style="font-family: "> HttpServlet {<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff6600; font-family: ">PrintWriter output;<span style="color: #0000ff; font-family: ">//成员变量</span></span><br style="font-family: " />
            <br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;@Override<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;<wbr style="font-family: ">protected<wbr style="font-family: "> <wbr style="font-family: ">void<wbr style="font-family: "> service(HttpServletRequest request,<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <wbr style="font-family: ">HttpServletResponse<wbr style="font-family: "> response) <wbr style="font-family: ">throws<wbr style="font-family: "> ServletException, <br style="font-family: " />
            IOException {<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; response.setContentType("text/html;charset=gb2312");<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name = request.getParameter("name");<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; output=response.getWriter();<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <wbr style="font-family: ">try<wbr style="font-family: "> {<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.<em style="font-family: "><wbr style="font-family: ">sleep</em><wbr style="font-family: ">(5000);<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <wbr style="font-family: ">catch<wbr style="font-family: "> (InterruptedException e) {<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #ff6600">output.write(name);<br style="font-family: " />
            </span>&nbsp;&nbsp;&nbsp;&nbsp;}<br style="font-family: " />
            <br style="font-family: " />
            }</span><br />
            该实例中定义了一个实例变量<font style="line-height: 1.5em" size="3">output</font><wbr>，在<font style="line-height: 1.5em" size="3">service</font><wbr>方法中负责输出用户名，当一个用户访问该<font style="line-height: 1.5em" size="3">Servlet</font><wbr>时，程序会正常的运行，但当多个用户并发的访问时，就可能会出现其他的用户信息显示在另一个用户的浏览器上的问题，为了看到实际的效果，在这个程序中，我特做如下的处理：就是延时<font style="line-height: 1.5em" size="3">5000</font><wbr>毫秒，让第一个用户暂停在输出数据前。然后我们马上发起另一个请求，这种情况下就会出现如下的页面<br />
            第一次请求：<wbr></span><a href="http://127.0.0.1:8080/Test2/securityTest?name=a" target="_blank"><span style="font-family: 楷体_GB2312">http://127.0.0.1:8080/Test2/securityTest?name=a</span><wbr></a><wbr><br />
            <br />
            <span style="font-family: 楷体_GB2312">大家看到这页面什么数据也没有，就是说那姓名没有打印出来，那跑到哪里去了呢？看第二个用户请求的情况。<br />
            第二个用户请求地址：<font style="line-height: 1.5em" size="3">http://127.0.0.1:8080/Test2/securityTest?name=b</font><wbr><br />
            <br />
            可以看到，原来<font style="line-height: 1.5em" size="3">a</font><wbr>值已经打印到第二个用户的浏览器了。<br />
            可以想像在暂停<font style="line-height: 1.5em" size="3">5000</font><wbr>时间里，第二个用户请求这个<font style="line-height: 1.5em" size="3">servlet</font><wbr>，已经把<font style="line-height: 1.5em" size="3">output</font><wbr>的引用变成了第二个用户请求的<font style="line-height: 1.5em" size="3">output</font><wbr>值了，这样就解释了为什么会输出到第二个客户端的浏览的原因。<br />
            <br />
            从内存模型来看<font style="line-height: 1.5em" size="3">Servlet</font><wbr>的线程安全问题<span style="color: #0000ff">//不是很理解这一段<br />
            </span><font style="line-height: 1.5em" size="3">&nbsp;&nbsp; JAVA</font><wbr>的内存模型<font style="line-height: 1.5em" size="3">JMM(JAVA Memory Model)</font><wbr>主要是为了规定线程与内存的一些关系，既然<font style="line-height: 1.5em" size="3">Servlet</font><wbr>也是用线程技术，那么我们也从这方面寻找根本原因，根据<font style="line-height: 1.5em" size="3">JMM</font><wbr>，系统存在有主内存，<font style="line-height: 1.5em" size="3">JAVA</font><wbr>的实例变量（就是类变量吧）都是存在于主内存供其他内存使用，也就是对所有的线程都是共享的，而根据线程的特点：它是有自己的工作内存的，工作内存包括缓存和堆栈两部分，堆栈是专门用来存在方法中的局部变量的，而缓存则是主内存中变量的拷贝，缓存与主内存并不总是同步的，也就是缓存中的变量的修改可能没有立刻写到主存中，如下图：<br />
            <br />
            根据内存模型，我们可以得到如下的线程调度表：<br />
            </span>
            <center><span style="font-family: 楷体_GB2312">调度时刻</span></center><wbr>
            <center><span style="font-family: 楷体_GB2312"><font style="line-height: 1.5em" size="3">a</font><wbr>线程</span></center><wbr>
            <center><span style="font-family: 楷体_GB2312"><font style="line-height: 1.5em" size="3">b</font><wbr>线程</span></center><wbr>
            <center><span style="font-family: 楷体_GB2312">T1</span><wbr></center><wbr>
            <center><span style="font-family: 楷体_GB2312">访问<font style="line-height: 1.5em" size="3">Servlet</font><wbr>页面</span></center><wbr>
            <center></center><wbr>
            <center><span style="font-family: 楷体_GB2312">T2 </span><wbr></center><wbr>
            <center></center><wbr>
            <center><span style="font-family: 楷体_GB2312">访问<font style="line-height: 1.5em" size="3">Servlet</font><wbr>页面</span></center><wbr>
            <center><span style="font-family: 楷体_GB2312">T3 </span><wbr></center><wbr>
            <center><span style="font-family: 楷体_GB2312"><font style="line-height: 1.5em" size="3">output=a</font><wbr>的输出<font style="line-height: 1.5em" size="3">username=a</font><wbr>休眠<font style="line-height: 1.5em" size="3">5000</font><wbr>毫秒，让出<font style="line-height: 1.5em" size="3">CPU </font><wbr></span></center><wbr>
            <center></center><wbr>
            <center><span style="font-family: 楷体_GB2312">T4 </span><wbr></center><wbr>
            <center></center><wbr>
            <center><span style="font-family: 楷体_GB2312"><font style="line-height: 1.5em" size="3">output=b</font><wbr>的输出（写回主存）<font style="line-height: 1.5em" size="3">username=b</font><wbr>休眠<font style="line-height: 1.5em" size="3">5000</font><wbr>毫秒，让出<font style="line-height: 1.5em" size="3">CPU</font><wbr></span></center><wbr>
            <center><span style="font-family: 楷体_GB2312">T5 </span><wbr></center><wbr>
            <center><span style="font-family: 楷体_GB2312">在用户<font style="line-height: 1.5em" size="3">b</font><wbr>的浏览器上输出<font style="line-height: 1.5em" size="3">a</font><wbr>线程的<font style="line-height: 1.5em" size="3">username</font><wbr>的值<font style="line-height: 1.5em" size="3">,a</font><wbr>线程终止。</span></center><wbr>
            <center></center><wbr>
            <center><span style="font-family: 楷体_GB2312">T6</span><wbr></center><wbr>
            <center></center><wbr>
            <center><span style="font-family: 楷体_GB2312">在用户<font style="line-height: 1.5em" size="3">b</font><wbr>的浏览器上输出<font style="line-height: 1.5em" size="3">b</font><wbr>线程的<font style="line-height: 1.5em" size="3">username</font><wbr>的值<font style="line-height: 1.5em" size="3">,b</font><wbr>线程终止。</span></center><wbr><br />
            <span style="font-family: 楷体_GB2312">可以看出，由于<font style="line-height: 1.5em" size="3">b</font><wbr>线程对实例变量<font style="line-height: 1.5em" size="3">output</font><wbr>的修改覆盖了<font style="line-height: 1.5em" size="3">a</font><wbr>线程对实例变量<font style="line-height: 1.5em" size="3">output</font><wbr>的值，直接导致了用户<font style="line-height: 1.5em" size="3">a</font><wbr>的信息显示到<font style="line-height: 1.5em" size="3">b</font><wbr>的浏览器上。根据内存模型，我们也可以解释到，正是因为<font style="line-height: 1.5em" size="3">b</font><wbr>开始时修改了缓存中的<font style="line-height: 1.5em" size="3">output</font><wbr>值，然后刷新到主内存中，而又有足够的时间刷新到<font style="line-height: 1.5em" size="3">a</font><wbr>缓存中，这时<font style="line-height: 1.5em" size="3">a</font><wbr>的<font style="line-height: 1.5em" size="3">Output</font><wbr>值就直接导致了指向<font style="line-height: 1.5em" size="3">b</font><wbr>浏览器。<br />
            解决方法：</strong><wbr><br />
            从上面的分析中，我们知道导致线程不安全的主要原因在于实例变量的使用不当，下面就提出如下三种解决方法<br />
            <font style="line-height: 1.5em" size="3"><span style="color: #ff0000"><font style="line-height: 1.5em" size="3">第一，</font><wbr>让<font style="line-height: 1.5em" size="3">Servlet</font><wbr>类实现<font style="line-height: 1.5em" size="3">SingleThreadModel</font><wbr>接口</span></font>，该接口指定系统如何处理对同一个<font style="line-height: 1.5em" size="3">Servlet</font><wbr>的调用，如果一个<font style="line-height: 1.5em" size="3">Servlet</font><wbr>被指定实现这个接口，那么，在这个<font style="line-height: 1.5em" size="3">Servlet</font><wbr>中的<font style="line-height: 1.5em" size="3">service</font><wbr>方法将不会在两个线程中同时执行，也就是说执行完一个后再执行下一个请求的<font style="line-height: 1.5em" size="3">service</font><wbr>，当然也就不存在线程不安全的问题了。<br />
            代码如下：<br />
            <strong><wbr>public</strong><wbr> <strong><wbr>class</strong><wbr> SecurityTest <strong><wbr>extends</strong><wbr> HttpServlet implements SingleThreadModel{}<br />
            其实这方法也就相当于是同步方法的效果吧。<br />
            <br />
            <span style="color: #ff0000">第二．同步对共享数据的操作</span>。我们所熟悉的就是用<font style="line-height: 1.5em" size="3">synchronized</font><wbr>关键字，这样能保证一次只有一个线程来操作被保护的区段。在本例子也可以用<font style="line-height: 1.5em" size="3">synchronized</font><wbr>来保证线程的安全，代码如下：<br />
            <wbr><span style="font-family: Comic Sans MS">public<wbr style="font-family: "> <wbr style="font-family: ">class<wbr style="font-family: "> SecurityTest <wbr style="font-family: ">extends<wbr style="font-family: "> HttpServlet {<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;PrintWriter output;<br style="font-family: " />
            <br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;@Override<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;<wbr style="font-family: ">protected<wbr style="font-family: "> <wbr style="font-family: ">void<wbr style="font-family: "> service(HttpServletRequest request,<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u style="font-family: "><wbr style="font-family: ">HttpServletResponse</u><wbr style="font-family: "> response) <wbr style="font-family: ">throws<wbr style="font-family: "> ServletException, IOException {<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; response.setContentType("text/html;charset=gb2312");<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name = request.getParameter("name");</span><br />
            <span style="color: #ff0000">Synchronized(this){</span><br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: Comic Sans MS">output=response.getWriter();<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <wbr style="font-family: ">try<wbr style="font-family: "> {<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.<em style="font-family: "><wbr style="font-family: ">sleep</em><wbr style="font-family: ">(5000);<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <wbr style="font-family: ">catch<wbr style="font-family: "> (InterruptedException e) {<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; output.write(name);<br style="font-family: " />
            </span><span style="color: #ff0000">}<br />
            </span>&nbsp;&nbsp;&nbsp;&nbsp;}}<br />
            <span style="color: #ff0000"><strong>第三：避免使用实例变量，而使用局部变量。</strong></span>因为Servlet线程不安全的原因是由实例变量引起，所以我们可以避免使用实例变量，而使用局部变量，线程之间很难直接访问局部变量 ，这样就从根本上解决了这一问题。<br />
            在本例子中，就是将output放在service方法中当局部变量 。<br />
            <wbr><span style="font-family: Comic Sans MS">public<wbr style="font-family: "> <wbr style="font-family: ">class<wbr style="font-family: "> SecurityTest <wbr style="font-family: ">extends<wbr style="font-family: "> HttpServlet {<br style="font-family: " />
            <br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;@Override<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;<wbr style="font-family: ">protected<wbr style="font-family: "> <wbr style="font-family: ">void<wbr style="font-family: "> service(HttpServletRequest request,<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpServletResponse response) <wbr style="font-family: ">throws<wbr style="font-family: "> ServletException, IOException {<br style="font-family: " />
            <span style="color: #ff6600">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PrintWriter output;<br style="font-family: " />
            </span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; response.setContentType("text/html;charset=gb2312");<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name = request.getParameter("name");<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; output=response.getWriter();<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <wbr style="font-family: ">try<wbr style="font-family: "> {<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.<em style="font-family: "><wbr style="font-family: ">sleep</em><wbr style="font-family: ">(5000);<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <wbr style="font-family: ">catch<wbr style="font-family: "> (InterruptedException e) {<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff6600">&nbsp;output.write(name);</span><br style="font-family: " />
            &nbsp;&nbsp;&nbsp;&nbsp;}<font style="line-height: 1.5em; font-family: " size="3">}</font></span><wbr><br />
            这三种方法都对解决servlet线程安全起到很好的作用，但我们如果对他们进行比较一下，看哪一种更适合呢：<br />
            第一个方案中：实现SingleThreadModel接口，Servlet引擎将为每个客户请求都生成一个Servlet实例，这将引起大量的系统开销，在新版本的Servlet2.4中也不提倡使用了。<br />
            第二个方案中：在程序中使用同步来保护要使用的共享数据，也使系统的性能大大的下降，这是因为被同步的代码在同一时刻只能由一个线程来执行，使得同时处理其他客户请求的吞吐量大大降低，大量客户处于阻塞状态，这对于并发用户请求来说并非是一件很好的事情。另外为了保持主内存与工作内存数据的一致性要频繁地刷新缓存，这也大大降低了系统性能，所以这种方案不大可取。<br />
            <span style="color: #008000"><strong>第三个方案则应该是最优方案：从JAVA内存模型来看，方法中的临时变量都是在栈中分配空间，而每个线程都有自己的私有栈空间，互不干扰，不会影响性能，也不会产生线程安全的问题。</strong></span></span></div>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</div>
<img src ="http://www.blogjava.net/yeping573/aggbug/267180.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yeping573/" target="_blank">王业平</a> 2009-04-23 16:31 <a href="http://www.blogjava.net/yeping573/archive/2009/04/23/267180.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于FileFilter使用的一点心得</title><link>http://www.blogjava.net/yeping573/archive/2009/04/23/267131.html</link><dc:creator>王业平</dc:creator><author>王业平</author><pubDate>Thu, 23 Apr 2009 05:54:00 GMT</pubDate><guid>http://www.blogjava.net/yeping573/archive/2009/04/23/267131.html</guid><wfw:comment>http://www.blogjava.net/yeping573/comments/267131.html</wfw:comment><comments>http://www.blogjava.net/yeping573/archive/2009/04/23/267131.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/yeping573/comments/commentRss/267131.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yeping573/services/trackbacks/267131.html</trackback:ping><description><![CDATA[<span style="color: red; font-family: 楷体_GB2312"><strong>现在要求输入一个文件的目录，之后将里面所有的备份文件删除，备份文件都是以&#8220;.bak&#8221;或".BAK"结尾<br />
<br />
</strong>
<p><span style="color: #339966"><strong>package TestFile;</strong></span></p>
<p><span style="color: #339966"><strong>import java.io.File;<br />
import java.io.FileFilter;</strong><br />
<strong><span style="color: #0000ff">/**<br />
&nbsp;* @author 王业平<br />
&nbsp;* 用于过滤以.bak结尾或包含.bak的文件<br />
&nbsp;* 返回值的含义是 当包含该字符串时返回true<br />
&nbsp;*/</span><br />
</strong><span style="font-family: Comic Sans MS">public class ListFilter implements FileFilter{<br style="font-family: " />
&nbsp;@Override<br style="font-family: " />
&nbsp;public boolean accept(File file) {</span><br />
<strong>&nbsp;&nbsp;&nbsp;&nbsp;</strong><span style="color: #0000ff"><strong>//测试指定的文件（夹）是否应该包含在指定的列表中（就是测定作为过滤的条件是否满足）<br />
&nbsp;&nbsp;/*<br />
&nbsp;&nbsp; * 如果是目录的话，直接返回true 表示是满足条件的一情况<br />
&nbsp;&nbsp; */<br />
</strong></span>&nbsp;<span style="color: #000000"><span style="color: #008000; font-family: Comic Sans MS">&nbsp;if(file.isDirectory()) return true;</span><br />
</span><strong>&nbsp;&nbsp;</strong><span style="color: #0000ff"><strong>/*<br />
&nbsp;&nbsp; * 如果不是目录的话，通过判断在其名字里是否含有规定的字符，<br />
&nbsp;&nbsp;&nbsp;* 因为string的index方法在不满足条件（不含有指定的字符）是返回-1<br />
&nbsp;&nbsp; * 所以以此来确定是否满足条件<br />
&nbsp;&nbsp; */<br />
</strong></span><span style="font-family: Comic Sans MS">&nbsp;&nbsp;String name=file.getName();<br style="font-family: " />
<span style="color: #0000ff">&nbsp;&nbsp;&nbsp;&nbsp;/*<br />
&nbsp;&nbsp;&nbsp;&nbsp; * int index=name.indexOf(".bak");&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; *</span>&nbsp;<span style="color: #0000ff">return index!=-1;<br />
<span style="font-family: 楷体_GB2312"><strong>&nbsp;&nbsp;* 这种方法不安全，可能会删除文件名中还含有.bak的文件，备份文件还可以用.BAK结尾<br />
</strong></span>&nbsp;&nbsp;&nbsp;&nbsp;*/<br />
&nbsp;&nbsp;<span style="color: #008000">&nbsp; return name.endsWith(".bak")||name.endsWith(".BAK");</span><br style="font-family: " />
</span><br style="font-family: " />
&nbsp;}<br style="font-family: " />
}</span><br />
<br />
<span style="font-family: Comic Sans MS">使用此类<br />
</span></p>
<p><span style="font-family: Comic Sans MS">package TestFile;</span></p>
<p><span style="font-family: Comic Sans MS">import java.io.File;</span><br />
<span style="color: #0000ff"><strong>/** <br />
&nbsp;* @author Administrator<br />
&nbsp;* 涉及到递归调用<br />
&nbsp;*/</strong></span></p>
<p style="font-family: Comic Sans MS">public class BakDelete{<br />
&nbsp;public static void main(String[] args){<br />
&nbsp;&nbsp;BakDelete bd=new BakDelete();<br />
&nbsp;&nbsp;bd.listBakFile(new File("E:\\"));<br />
&nbsp;}<br />
&nbsp;public void listBakFile(File file){<br />
&nbsp;&nbsp;File[] fs=file.listFiles(<span style="color: #ff0000">ne</span><span style="color: #ff0000">w ListFilter()<span style="color: #339966">);</span></span><br />
&nbsp;&nbsp;for(int i=0;i&lt;fs.length;i++){<br />
&nbsp;&nbsp;&nbsp;if(fs[i].isFile()){<br />
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(fs[i].getAbsolutePath());<span style="color: #0000ff">//打印文件绝对路径</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;fs[i].delete();<br />
&nbsp;&nbsp;&nbsp;}else{<br />
&nbsp;&nbsp;&nbsp;&nbsp;//System.out.println(fs[i].getAbsolutePath());<br />
&nbsp;&nbsp;&nbsp;&nbsp;listBakFile(fs[i]);<br />
&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;//System.out.println(fs.length);<br />
&nbsp;}<br />
}</p>
</span></span>
<img src ="http://www.blogjava.net/yeping573/aggbug/267131.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yeping573/" target="_blank">王业平</a> 2009-04-23 13:54 <a href="http://www.blogjava.net/yeping573/archive/2009/04/23/267131.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>