﻿<?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-Calvin's Tech Space-随笔分类-Java</title><link>http://www.blogjava.net/lihao336/category/41614.html</link><description>成于坚忍，毁于浮躁</description><language>zh-cn</language><lastBuildDate>Sat, 26 Nov 2011 06:04:41 GMT</lastBuildDate><pubDate>Sat, 26 Nov 2011 06:04:41 GMT</pubDate><ttl>60</ttl><item><title>InputStream.available()方法</title><link>http://www.blogjava.net/lihao336/archive/2011/11/18/364225.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Fri, 18 Nov 2011 06:16:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/11/18/364225.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/364225.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/11/18/364225.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/364225.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/364225.html</trackback:ping><description><![CDATA[首先这个方法不能用来判断文件长度！获取文件长度可以使用File.length()方法，它返回一个long类型的以字节为单位的值。<br /><br />看文档：<br />Returns an estimated number of bytes that can be read or skipped without blocking for more input.<br /><br /><b>Note that this method provides such a weak guarantee that it is not very useful in practice.</b><br /><br />Firstly, the guarantee is "without blocking for more input" rather than "without blocking": a read may still block waiting for I/O to complete — the guarantee is merely that it won't have to wait indefinitely for data to be written. The result of this method should not be used as a license to do I/O on a thread that shouldn't be blocked.<br /><br />Secondly, the result is a conservative estimate and may be significantly smaller than the actual number of bytes available. In particular, an implementation that always returns 0 would be correct. In general, callers should only use this method if they'd be satisfied with treating the result as a boolean yes or no answer to the question "is there definitely data ready?".<br /><br />Thirdly, the fact that a given number of bytes is "available" does not guarantee that a read or skip will actually read or skip that many bytes: they may read or skip fewer.<br /><br /><b>It is particularly important to realize that you must not use this method to size a container and assume that you can read the entirety of the stream without needing to resize the container. Such callers should probably write everything they read to a ByteArrayOutputStream and convert that to a byte array. Alternatively, if you're reading from a file, length() returns the current length of the file (though assuming the file's length can't change may be incorrect, reading a file is inherently racy).</b><br /><br />The default implementation of this method in InputStream always returns 0. Subclasses should override this method if they are able to indicate the number of bytes available.<br /><br /><img src ="http://www.blogjava.net/lihao336/aggbug/364225.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-11-18 14:16 <a href="http://www.blogjava.net/lihao336/archive/2011/11/18/364225.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>重写equals和hashCode方法</title><link>http://www.blogjava.net/lihao336/archive/2011/11/10/363457.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Thu, 10 Nov 2011 10:25:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/11/10/363457.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/363457.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/11/10/363457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/363457.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/363457.html</trackback:ping><description><![CDATA[以下总结自effective java.<br />实现equals方法的过程如下：<br />1 使用==运算符来判断是否引用同一个对象。<br />2 使用instance of操作符来判断参数是否是正确的类型。<br />3 将实参cast成正确的类型。<br />4 对于每个关键属性，进行比较:<br />对于非float或double的primitive类型，使用==判断等价性;<br />对于floa类型，先使用Float.floatToIntBits转换成int类型，然后使用==比较int类型的值;<br />对于double类型，先使用Double.doubleToLongBits转换成long类型，然后使用==比较long类型;<br />对于对象引用，递归的调用equals方法。<br />对于数组类型，对其中的元素进行上述的操作,或者使用Arrays.equals方法(version 1.5)。<br />为了避免NPE，可以使用<br />field == null ? o.field == null : fleld.equals(o.field);<br /><br />重写hashCode方法如下：<br />1 把某个非零常数值，例如17，保存在int变量result中；<br />2 对于对象中每一个关键域f（指equals方法中考虑的每一个域）,计算散列码c：<br />2.1 boolean型，计算(f ? 0 : 1);<br />2.2 byte,char,short型，计算(int);<br />2.3 long型，计算(int) (f ^ (f&gt;&gt;&gt;32));<br />2.4 float型，计算Float.floatToIntBits(f);<br />2.5 double型，计算Double.doubleToLongBits(f)得到一个long，再执行[2.3];<br />2.6 对象引用，递归调用它的hashCode方法;<br />2.7 数组域，对其中每个元素按照上面的规则计算hash code。<br />3 将上面计算得到的散列码保存到int变量c，然后执行 result=37*result+c;<br />4 返回result。<br /><br /><img src ="http://www.blogjava.net/lihao336/aggbug/363457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-11-10 18:25 <a href="http://www.blogjava.net/lihao336/archive/2011/11/10/363457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用javap生成方法签名</title><link>http://www.blogjava.net/lihao336/archive/2011/10/24/361901.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Mon, 24 Oct 2011 08:04:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/10/24/361901.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/361901.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/10/24/361901.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/361901.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/361901.html</trackback:ping><description><![CDATA[使用JNI在native内调用java方法时，需要知道java方法的方法签名，利用javap工具可以方便的生成签名。由于java方法签名在jni层的表示方法的复杂性，利用这个工具生成签名信息可以避免人工分析带来的错误。<br />如：<br /><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008080; "> 1</span> <span style="color: #0000FF; ">package</span><span style="color: #000000; "> com.demo;<br /></span><span style="color: #008080; "> 2</span> <span style="color: #000000; "><br /></span><span style="color: #008080; "> 3</span> <span style="color: #000000; "></span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">class</span><span style="color: #000000; "> SigTest {<br /></span><span style="color: #008080; "> 4</span> <span style="color: #000000; "><br /></span><span style="color: #008080; "> 5</span> <span style="color: #000000; ">    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">static</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">final</span><span style="color: #000000; "> String name </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">;<br /></span><span style="color: #008080; "> 6</span> <span style="color: #000000; "><br /></span><span style="color: #008080; "> 7</span> <span style="color: #000000; ">    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> getName(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">[] data,</span><span style="color: #0000FF; ">long</span><span style="color: #000000; "> index) {<br /></span><span style="color: #008080; "> 8</span> <span style="color: #000000; ">        </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> </span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br /></span><span style="color: #008080; "> 9</span> <span style="color: #000000; ">    }<br /></span><span style="color: #008080; ">10</span> <span style="color: #000000; ">}<br /></span><span style="color: #008080; ">11</span> <span style="color: #000000; "></span></div><br />[calvin@calvin-desktop /tmp 15:59:50 ] <br />$ javac SigTest.java <br />[calvin@calvin-desktop /tmp 15:59:57 ] <br />$ javap -s -p -classpath . <b>SigTest</b><br />Compiled from "SigTest.java"<br />public class com.demo.SigTest extends java.lang.Object{<br />public static final java.lang.String name;<br />  Signature: Ljava/lang/String;<br />public com.demo.SigTest();<br />  Signature: ()V<br />public int getName(int[], long);<br />  Signature: ([IJ)I<br />static {};<br />  Signature: ()V<br />}<br /><br /><br />-s表示打印签名信息<br />-p表示打印所有函数和成员的签名信息，默认只打印public的签名信息。<br /><br />注意：<br />粗体部分是.class文件的文件名，不要.class后缀，否则提示<br />ERROR:Could not find SigTest.class.<br /><br /><img src ="http://www.blogjava.net/lihao336/aggbug/361901.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-10-24 16:04 <a href="http://www.blogjava.net/lihao336/archive/2011/10/24/361901.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java foreach与泛型擦除</title><link>http://www.blogjava.net/lihao336/archive/2011/06/17/352540.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Fri, 17 Jun 2011 10:47:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/06/17/352540.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/352540.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/06/17/352540.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/352540.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/352540.html</trackback:ping><description><![CDATA[
		<br />如下代码：<br /><br /><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008080; ">1</span> <span style="color: #000000; ">        List appleList </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> ArrayList</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">String</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">();<br /></span><span style="color: #008080; ">2</span> <span style="color: #000000; ">        </span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">(String apple:appleList){<br /></span><span style="color: #008080; ">3</span> <span style="color: #000000; ">            </span><span style="color: #008000; ">//</span><span style="color: #008000; ">blabla</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">4</span> <span style="color: #008000; "></span><span style="color: #000000; ">        }</span></div><br /><br /><br />编译器 complains:Type mismatch: cannot convert from element type Object to String<br /><br />http://www.infoq.com/cn/articles/cf-java-generics<br /><br /><br /><img src ="http://www.blogjava.net/lihao336/aggbug/352540.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-06-17 18:47 <a href="http://www.blogjava.net/lihao336/archive/2011/06/17/352540.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>chechstyle异常 “Static variable definition in wrong order”</title><link>http://www.blogjava.net/lihao336/archive/2011/02/12/344112.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sat, 12 Feb 2011 02:52:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2011/02/12/344112.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/344112.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2011/02/12/344112.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/344112.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/344112.html</trackback:ping><description><![CDATA[原因在于变量声明的顺序不正确。<br />
<br />
参见 <br />
<a href="http://java.sun.com/docs/codeconv/html/CodeConventions.doc2.html#1852">http://java.sun.com/docs/codeconv/html/CodeConventions.doc2.html#1852</a><br />
<br />
<img src ="http://www.blogjava.net/lihao336/aggbug/344112.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2011-02-12 10:52 <a href="http://www.blogjava.net/lihao336/archive/2011/02/12/344112.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>When Runtime.exec() won't</title><link>http://www.blogjava.net/lihao336/archive/2010/11/23/338787.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 23 Nov 2010 05:49:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/11/23/338787.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/338787.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/11/23/338787.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/338787.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/338787.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: When Runtime.exec() won'thttp://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.htmlWhen Runtime.exec() won'tNavigate yourself around pitfalls related to the Runtime.exec() methodSummar...&nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/11/23/338787.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/338787.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-11-23 13:49 <a href="http://www.blogjava.net/lihao336/archive/2010/11/23/338787.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何中断线程</title><link>http://www.blogjava.net/lihao336/archive/2010/10/29/336496.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Fri, 29 Oct 2010 08:44:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/10/29/336496.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/336496.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/10/29/336496.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/336496.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/336496.html</trackback:ping><description><![CDATA[1.不要使用thread.stop()方法。<br />
2.使用共享变量来检查是否需要终止线程。<br />
但是如果线程被阻塞了，它就不可能去主动去检查变量了，这时要使用thread.interrupt来中断线程吗？<br />
谨慎使用thread.interrupt方法！<br />
<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><strong><span style="color: #000000;">Thread.interrupt()方法不会中断一个正在运行的线程。这一方法实际上完成的是，在线程受到阻塞时抛出一个中断信号，这样线程就得以退出阻塞的状态。更确切的说，如果线程被Object.wait,&nbsp;Thread.join和Thread.sleep三种方法之一阻塞，那么，它将接收到一个中断异常（InterruptedException），从而提早地终结被阻塞状态。<br />
<br />
</span>因此，如果线程被上述几种方法阻塞，正确的停止线程方式时设置共享变量，并调用interrupt()（注意变量应该先设置）。如果线程没有被阻塞，这时调用interrupt()将不起作用；否则，线程就将得到异常（该线程必须事先预备好处理此状况），接着逃离阻塞状态。在任何一种情况中，线程</strong><strong>最后</strong><strong>都将检查共享变量然后再停止。</strong><br />
<br />
<br />
<strong>中断标志必须是<span style="color: red;">volatile</span>的，以便run方法能够看到它，否则的话，这个值很有可能在本地有缓存。</strong><br />
</div>
<br />
线程代码为：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()&nbsp;{&nbsp;&nbsp;<br />
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(running)&nbsp;{&nbsp; </span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{&nbsp;&nbsp;<br />
</span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #008000;">//&nbsp;do&nbsp;something&nbsp;may&nbsp;block...</span><span style="color: #008000;"><br />
<br />
</span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(InterruptedException&nbsp;e)&nbsp;{&nbsp;&nbsp;<br />
</span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;running&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;&nbsp; </span><span style="color: #000000;"><br />
</span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
</span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;<br />
</span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">while&nbsp;&nbsp;<br />
</span><span style="color: #008080;">15</span>&nbsp;<span style="color: #008000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;"><img src="../../Images/dot.gif" alt="" />.&nbsp;&nbsp;</span><span style="color: #008000;"><br />
</span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">}&nbsp; <br />
</span></div>
<br />
需要停止线程时，调用：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><span style="color: #008080;">1</span>&nbsp;<span style="color: #000000;">running&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">thread.interrupt();</span></div>
<br />
注意，一定要先设置标志位后再调用interrupt！<br />
<br />
如果线程因为其他原因阻塞，例如<span class="Apple-style-span" style="border-collapse: separate; color: #000000; font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"><span class="Apple-style-span" style="font-family: verdana,sans-serif; font-size: 14px; line-height: 21px; text-align: left;">socket.accept()</span></span>，这时，调用interrupt不会抛出异常，又该如何处理？<br />
这些情况下，需要分别处理，例如在socket上调用close方法，它将抛出一个SocketException，这与抛出InterruptException类似。<span class="Apple-style-span" style="border-collapse: separate; color: #000000; font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"></span><br />
<br />
参考：<br />
1、<a href="http://blog.csdn.net/nihaozhangchao/archive/2010/01/07/5147803.aspx">http://blog.csdn.net/nihaozhangchao/archive/2010/01/07/5147803.aspx</a><br />
2、<a href="http://blog.chenlb.com/2009/07/incorrect-use-thread-interrupt-cause-not-exit.html">http://blog.chenlb.com/2009/07/incorrect-use-thread-interrupt-cause-not-exit.html</a><br />
<img src ="http://www.blogjava.net/lihao336/aggbug/336496.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-10-29 16:44 <a href="http://www.blogjava.net/lihao336/archive/2010/10/29/336496.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>线程相关知识点</title><link>http://www.blogjava.net/lihao336/archive/2010/10/29/336493.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Fri, 29 Oct 2010 07:23:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/10/29/336493.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/336493.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/10/29/336493.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/336493.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/336493.html</trackback:ping><description><![CDATA[<strong>线程概念</strong><br />
线程：是指进程中的一个执行流程。 <br />
线程与进程的区别：每个进程都需要操作系统为其分配独立的内存地址空间，而同一进程中的所有线程在同一块地址空间中工作，这些线程可以共享同一块内存和系统资源。 <br />
<br />
<strong>如何创建一个线程？ </strong><br />
创建线程有两种方式，如下： <br />
1、	扩展java.lang.Thread类 <br />
2、	实现Runnable接口 <br />
Thread类代表线程类，它的两个最主要的方法是： <br />
run()——包含线程运行时所执行的代码 <br />
Start()——用于启动线程 <br />
<br />
一个线程被创建后只能被启动一次。第二次启动时将会抛出java.lang.IllegalThreadExcetpion异常 <br />
<br />
<strong>线程间状态的转换</strong><br />
新建状态：用new语句创建的线程对象处于新建状态，此时它和其它的java对象一样，仅仅在堆中被分配了内存 <br />
就绪状态：当一个线程创建了以后，其他的线程调用了它的start()方法，该线程就进入了就绪状态。处于这个状态的线程位于可运行池中，等待获得CPU的使用权 <br />
运行状态：处于这个状态的线程占用CPU,执行程序的代码 <br />
阻塞状态：当线程处于阻塞状态时，java虚拟机不会给线程分配CPU，直到线程重新进入就绪状态，它才有机会转到运行状态。 <br />
阻塞状态分为三种情况： <br />
1、	位于对象等待池中的阻塞状态：当线程运行时，如果执行了某个对象的wait()方法，java虚拟机就回把线程放到这个对象的等待池中 <br />
2、	位于对象锁中的阻塞状态，当线程处于运行状态时，试图获得某个对象的同步锁时，如果该对象的同步锁已经被其他的线程占用，JVM就会把这个线程放到这个对象的琐池中。 <br />
3、	其它的阻塞状态：<br />
<ul>
    <li>当前线程执行了sleep()方法</li>
    <li>调用了其它线程的join()方法</li>
    <li>发出了I/O请求时 </li>
</ul>
死亡状态：当线程退出了run()方法，就进入了死亡状态，该线程结束了生命周期。 <br />
或者正常退出 <br />
或者遇到异常退出 <br />
<br />
Thread类的isAlive()方法判断一个线程是否活着，当线程处于死亡状态或者新建状态时，该方法返回false,在其余的状态下，该方法返回true. <br />
<br />
<strong>线程调度 </strong><br />
线程调度模型：分时调度模型和抢占式调度模型 <br />
JVM采用抢占式调度模型。 <br />
所谓的多线程的并发运行，其实是指宏观上看，各个线程轮流获得CPU的使用权，分别执行各自的任务。 <br />
（线程的调度不是跨平台，它不仅取决于java虚拟机，它还依赖于操作系统） <br />
<br />
如果希望明确地让一个线程给另外一个线程运行的机会，可以采取以下的办法之一 <br />
1、	调整各个线程的优先级 <br />
2、	让处于运行状态的线程调用Thread.sleep()方法 <br />
3、	让处于运行状态的线程调用Thread.yield()方法 <br />
4、	让处于运行状态的线程调用另一个线程的join()方法 <br />
<br />
调整各个线程的优先级 <br />
Thread类的setPriority(int)和getPriority()方法分别用来设置优先级和读取优先级。 <br />
如果希望程序能够移值到各个操作系统中，应该确保在设置线程的优先级时，只使用MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITY这3个优先级。 <br />
<br />
线程睡眠：当线程在运行中执行了sleep()方法时，它就会放弃CPU，转到阻塞状态。 <br />
线程让步：当线程在运行中执行了Thread类的yield()静态方法时，如果此时具有相同优先级的其它线程处于就绪状态，那么yield()方法将把当前运行的线程放到运行池中并使另一个线程运行。如果没有相同优先级的可运行线程，则yield()方法什么也不做。 <br />
Sleep()方法和yield()方法都是Thread类的静态方法，都会使当前处于运行状态的线程放弃CPU，把运行机会让给别的线程，两者的区别在于： <br />
1、sleep()方法会给其他线程运行的机会，而不考虑其他线程的优先级，因此会给较低线程一个运行的机会；yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。 <br />
2、当线程执行了sleep(long millis)方法后，将转到阻塞状态，参数millis指定睡眠时间；当线程执行了yield()方法后，将转到就绪状态。 <br />
3、sleep()方法声明抛出InterruptedException异常，而yield()方法没有声明抛出任何异常 <br />
4、sleep()方法比yield()方法具有更好的移植性 <br />
<br />
等待其它线程的结束：join() <br />
当前运行的线程可以调用另一个线程的 join()方法，当前运行的线程将转到阻塞状态，直到另一个线程运行结束，它才恢复运行。 <br />
<br />
定时器Timer:在JDK的java.util包中提供了一个实用类Timer, 它能够定时执行特定的任务。 <br />
<br />
<strong>线程的同步 </strong><br />
原子操作：根据Java规范，对于基本类型的赋值或者返回值操作，是原子操作。但这里的基本数据类型不包括long和double, 因为JVM看到的基本存储单位是32位，而long 和double都要用64位来表示。所以无法在一个时钟周期内完成。 <br />
<br />
自增操作（++）不是原子操作，因为它涉及到一次读和一次写。 <br />
<br />
原子操作：由一组相关的操作完成，这些操作可能会操纵与其它的线程共享的资源，为了保证得到正确的运算结果，一个线程在执行原子操作其间，应该采取其他的措施使得其他的线程不能操纵共享资源。 <br />
<br />
同步代码块：为了保证每个线程能够正常执行原子操作，Java引入了同步机制，具体的做法是在代表原子操作的程序代码前加上synchronized标记，这样的代码被称为同步代码块。 <br />
<br />
同步锁：每个JAVA对象都有且只有一个同步锁，在任何时刻，最多只允许一个线程拥有这把锁。 <br />
<br />
当一个线程试图访问带有synchronized(this)标记的代码块时，必须获得 this关键字引用的对象的锁，在以下的两种情况下，本线程有着不同的命运。 <br />
1、	假如这个锁已经被其它的线程占用，JVM就会把这个线程放到本对象的锁池中。本线程进入阻塞状态。锁池中可能有很多的线程，等到其他的线程释放了锁，JVM就会从锁池中随机取出一个线程，使这个线程拥有锁，并且转到就绪状态。 <br />
2、	假如这个锁没有被其他线程占用，本线程会获得这把锁，开始执行同步代码块。 <br />
（一般情况下在执行同步代码块时不会释放同步锁，但也有特殊情况会释放对象锁 <br />
如在执行同步代码块时，遇到异常而导致线程终止，锁会被释放；在执行代码块时，执行了锁所属对象的wait()方法，这个线程会释放对象锁，进入对象的等待池中） <br />
<br />
线程同步的特征： <br />
1、 如果一个同步代码块和非同步代码块同时操作共享资源，仍然会造成对共享资源的竞争。因为当一个线程执行一个对象的同步代码块时，其他的线程仍然可以执行对 象的非同步代码块。（所谓的线程之间保持同步，是指不同的线程在执行同一个对象的同步代码块时，因为要获得对象的同步锁而互相牵制） <br />
2、	每个对象都有唯一的同步锁 <br />
3、	在静态方法前面可以使用synchronized修饰符。 <br />
4、	当一个线程开始执行同步代码块时，并不意味着必须以不间断的方式运行，进入同步代码块的线程可以执行Thread.sleep()或者执行Thread.yield()方法，此时它并不释放对象锁，只是把运行的机会让给其他的线程。 <br />
5、	Synchronized声明不会被继承，如果一个用synchronized修饰的方法被子类覆盖，那么子类中这个方法不在保持同步，除非用synchronized修饰。 <br />
<br />
线程安全的类： <br />
1、	这个类的对象可以同时被多个线程安全的访问。 <br />
2、	每个线程都能正常的执行原子操作，得到正确的结果。 <br />
3、	在每个线程的原子操作都完成后，对象处于逻辑上合理的状态。 <br />
<br />
释放对象的锁： <br />
1、	执行完同步代码块就会释放对象的锁 <br />
2、	在执行同步代码块的过程中，遇到异常而导致线程终止，锁也会被释放 <br />
3、	在执行同步代码块的过程中，执行了锁所属对象的wait()方法，这个线程会释放对象锁，进入对象的等待池。 <br />
<br />
死锁 <br />
当一个线程等待由另一个线程持有的锁，而后者正在等待已被第一个线程持有的锁时，就会发生死锁。JVM不监测也不试图避免这种情况，因此保证不发生死锁就成了程序员的责任。 <br />
<br />
如何避免死锁 <br />
一个通用的经验法则是：当几个线程都要访问共享资源A、B、C 时，保证每个线程都按照同样的顺序去访问他们。 <br />
<br />
线程通信 <br />
Java.lang.Object类中提供了两个用于线程通信的方法 <br />
1、	wait():执行了该方法的线程释放对象的锁，JVM会把该线程放到对象的等待池中。该线程等待其它线程唤醒 <br />
2、	notify():执行该方法的线程唤醒在对象的等待池中等待的一个线程，JVM从对象的等待池中随机选择一个线程，把它转到对象的锁池中。
<div>转自&nbsp;<a href="http://blog.csdn.net/Android_Tutor/archive/2010/02/06/5293974.aspx">http://blog.csdn.net/Android_Tutor/archive/2010/02/06/5293974.aspx</a></div>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<img src ="http://www.blogjava.net/lihao336/aggbug/336493.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-10-29 15:23 <a href="http://www.blogjava.net/lihao336/archive/2010/10/29/336493.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UTF-8文件头乱码问题</title><link>http://www.blogjava.net/lihao336/archive/2010/07/27/327231.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 27 Jul 2010 08:38:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/07/27/327231.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/327231.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/07/27/327231.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/327231.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/327231.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/07/27/327231.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/327231.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-07-27 16:38 <a href="http://www.blogjava.net/lihao336/archive/2010/07/27/327231.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CruiseControl配置说明</title><link>http://www.blogjava.net/lihao336/archive/2010/06/29/324822.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 29 Jun 2010 12:31:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/06/29/324822.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/324822.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/06/29/324822.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/324822.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/324822.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/06/29/324822.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/324822.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-06-29 20:31 <a href="http://www.blogjava.net/lihao336/archive/2010/06/29/324822.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HashMap，TreeMap，LinkedHashMap比较</title><link>http://www.blogjava.net/lihao336/archive/2010/05/21/321547.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Fri, 21 May 2010 07:51:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/05/21/321547.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/321547.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/05/21/321547.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/321547.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/321547.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/05/21/321547.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/321547.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-05-21 15:51 <a href="http://www.blogjava.net/lihao336/archive/2010/05/21/321547.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>cruisecontrol参考</title><link>http://www.blogjava.net/lihao336/archive/2010/05/20/321439.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Thu, 20 May 2010 01:27:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/05/20/321439.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/321439.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/05/20/321439.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/321439.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/321439.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/05/20/321439.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/321439.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-05-20 09:27 <a href="http://www.blogjava.net/lihao336/archive/2010/05/20/321439.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>将字节数组转化位int</title><link>http://www.blogjava.net/lihao336/archive/2010/04/03/317421.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sat, 03 Apr 2010 15:42:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/04/03/317421.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/317421.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/04/03/317421.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/317421.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/317421.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/04/03/317421.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/317421.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-04-03 23:42 <a href="http://www.blogjava.net/lihao336/archive/2010/04/03/317421.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java对象的强、软、弱和虚引用</title><link>http://www.blogjava.net/lihao336/archive/2010/03/18/315843.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Thu, 18 Mar 2010 13:31:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/03/18/315843.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/315843.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/03/18/315843.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/315843.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/315843.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/03/18/315843.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/315843.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-03-18 21:31 <a href="http://www.blogjava.net/lihao336/archive/2010/03/18/315843.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用Ant时间戳</title><link>http://www.blogjava.net/lihao336/archive/2010/03/16/315610.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 16 Mar 2010 09:04:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/03/16/315610.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/315610.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/03/16/315610.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/315610.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/315610.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/03/16/315610.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/315610.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-03-16 17:04 <a href="http://www.blogjava.net/lihao336/archive/2010/03/16/315610.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSON相关</title><link>http://www.blogjava.net/lihao336/archive/2010/01/03/308113.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sun, 03 Jan 2010 14:47:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/01/03/308113.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/308113.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/01/03/308113.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/308113.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/308113.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/01/03/308113.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/308113.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-01-03 22:47 <a href="http://www.blogjava.net/lihao336/archive/2010/01/03/308113.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式Double-Checked Locking失效问题 </title><link>http://www.blogjava.net/lihao336/archive/2010/01/03/308100.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sun, 03 Jan 2010 11:55:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/01/03/308100.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/308100.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/01/03/308100.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/308100.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/308100.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/01/03/308100.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/308100.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-01-03 19:55 <a href="http://www.blogjava.net/lihao336/archive/2010/01/03/308100.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java散列集小结</title><link>http://www.blogjava.net/lihao336/archive/2010/01/03/308074.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sun, 03 Jan 2010 04:25:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/01/03/308074.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/308074.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/01/03/308074.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/308074.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/308074.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/01/03/308074.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/308074.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-01-03 12:25 <a href="http://www.blogjava.net/lihao336/archive/2010/01/03/308074.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Java多线程编程总结</title><link>http://www.blogjava.net/lihao336/archive/2010/01/01/307985.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Fri, 01 Jan 2010 09:30:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2010/01/01/307985.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/307985.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2010/01/01/307985.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/307985.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/307985.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2010/01/01/307985.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/307985.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2010-01-01 17:30 <a href="http://www.blogjava.net/lihao336/archive/2010/01/01/307985.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>非常有价值的NIO参考资料---The Rox Java NIO Tutorial</title><link>http://www.blogjava.net/lihao336/archive/2009/12/27/307433.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sun, 27 Dec 2009 05:55:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2009/12/27/307433.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/307433.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2009/12/27/307433.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/307433.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/307433.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2009/12/27/307433.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/307433.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2009-12-27 13:55 <a href="http://www.blogjava.net/lihao336/archive/2009/12/27/307433.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unix 5种IO模型的图解分析和比较</title><link>http://www.blogjava.net/lihao336/archive/2009/12/27/307430.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sun, 27 Dec 2009 05:32:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2009/12/27/307430.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/307430.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2009/12/27/307430.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/307430.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/307430.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2009/12/27/307430.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/307430.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2009-12-27 13:32 <a href="http://www.blogjava.net/lihao336/archive/2009/12/27/307430.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>同步/异步与阻塞/非阻塞的区别</title><link>http://www.blogjava.net/lihao336/archive/2009/12/27/307429.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sun, 27 Dec 2009 05:24:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2009/12/27/307429.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/307429.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2009/12/27/307429.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/307429.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/307429.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2009/12/27/307429.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/307429.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2009-12-27 13:24 <a href="http://www.blogjava.net/lihao336/archive/2009/12/27/307429.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java NIO（未完待续）</title><link>http://www.blogjava.net/lihao336/archive/2009/12/24/307217.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Thu, 24 Dec 2009 14:27:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2009/12/24/307217.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/307217.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2009/12/24/307217.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/307217.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/307217.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2009/12/24/307217.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/307217.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2009-12-24 22:27 <a href="http://www.blogjava.net/lihao336/archive/2009/12/24/307217.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unicode详解</title><link>http://www.blogjava.net/lihao336/archive/2009/12/22/306954.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 22 Dec 2009 15:19:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2009/12/22/306954.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/306954.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2009/12/22/306954.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/306954.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/306954.html</trackback:ping><description><![CDATA[<p><font style="background-color: #f4f4f4">版权声明：可以任意转载，但转载时必须标明原作者charlee、原始链接<a href="http://tech.idv2.com/2008/02/21/unicode-intro/">http://tech.idv2.com/2008/02/21/unicode-intro/</a>以及本声明。<br />
<br />
</font><font style="background-color: #f4f4f4"></p>
<p>可能大家都听说过 Unicode、UCS-2、UTF-8 等等词汇，但它们具体是什么意思， 是什么原理，之间有什么关系，恐怕就很少有人明白了。 下面就分别介绍一下它们。<br />
基本知识 <br />
字节和字符的区别<br />
Big Endian和Little Endian<br />
UCS-2和UCS-4<br />
UTF-16和UTF-32 <br />
UTF-16<br />
UTF-32<br />
UTF-8<br />
基本知识</p>
<p>介绍Unicode之前，首先要讲解一些基础知识。虽然跟Unicode没有直接的关系， 但想弄明白Unicode，没这些还真不行。<br />
字节和字符的区别</p>
<p>咦，字节和字符能有什么区别啊？不都是一样的吗？完全正确，但只是在古老的DOS时代。 当Unicode出现后，字节和字符就不一样了。</p>
<p>字节（octet）是一个八位的存储单元，取值范围一定是0～255。而字符（character，或者word） 为语言意义上的符号，范围就不一定了。例如在UCS-2中定义的字符范围为0～65535， 它的一个字符占用两个字节。<br />
Big Endian和Little Endian</p>
<p>上面提到了一个字符可能占用多个字节，那么这多个字节在计算机中如何存储呢？ 比如字符0xabcd，它的存储格式到底是 AB CD，还是 CD AB 呢？</p>
<p>实际上两者都有可能，并分别有不同的名字。如果存储为 AB CD，则称为Big Endian； 如果存储为 CD AB，则称为Little Endian。</p>
<p>具体来说，以下这种存储格式为Big Endian，因为值(0xabcd)的高位(0xab)存储在前面：地址&nbsp;值<br />
0x00000000&nbsp;AB<br />
0x00000001&nbsp;CD</p>
<p><br />
相反，以下这种存储格式为Little Endian：地址&nbsp;值<br />
0x00000000&nbsp;CD<br />
0x00000001&nbsp;AB</p>
<p>UCS-2和UCS-4</p>
<p>Unicode是为整合全世界的所有语言文字而诞生的。任何文字在Unicode中都对应一个值， 这个值称为代码点（code point，参见Java核心技术的相关章节！）。代码点的值通常写成 U+ABCD 的格式。 而文字和代码点之间的对应关系就是UCS-2（Universal Character Set coded in 2 octets）。 顾名思义，UCS-2是用两个字节来表示代码点，其取值范围为 U+0000～U+FFFF。</p>
<p>为了能表示更多的文字，人们又提出了UCS-4，即用四个字节表示代码点。 它的范围为 U+00000000～U+7FFFFFFF，其中 U+00000000～U+0000FFFF和UCS-2是一样的。</p>
<p>要注意，UCS-2和UCS-4只规定了代码点和文字之间的对应关系，并没有规定代码点在计算机中如何存储。 规定存储方式的称为UTF（Unicode Transformation Format），其中应用较多的就是UTF-16和UTF-8了。<br />
UTF-16和UTF-32<br />
UTF-16</p>
<p>UTF-16由RFC2781规定，它使用两个字节来表示一个代码点。</p>
<p>不难猜到，UTF-16是完全对应于UCS-2的，即把UCS-2规定的代码点通过Big Endian或Little Endian方式 直接保存下来。UTF-16包括三种：UTF-16，UTF-16BE（Big Endian），UTF-16LE（Little Endian）。</p>
<p>UTF-16BE和UTF-16LE不难理解，而UTF-16就需要通过在文件开头以名为BOM（Byte Order Mark）的字符 来表明文件是Big Endian还是Little Endian。BOM为U+FEFF这个字符。</p>
<p>其实BOM是个小聪明的想法。由于UCS-2没有定义U+FFFE， 因此只要出现 FF FE 或者 FE FF 这样的字节序列，就可以认为它是U+FEFF， 并且可以判断出是Big Endian还是Little Endian。</p>
<p>举个例子。&#8220;ABC&#8221;这三个字符用各种方式编码后的结果如下：UTF-16BE&nbsp;00 41 00 42 00 43<br />
UTF-16LE&nbsp;41 00 42 00 43 00<br />
UTF-16(Big Endian)&nbsp;FE FF 00 41 00 42 00 43<br />
UTF-16(Little Endian)&nbsp;FF FE 41 00 42 00 43 00<br />
UTF-16(不带BOM)&nbsp;00 41 00 42 00 43</p>
<p><br />
Windows平台下默认的Unicode编码为Little Endian的UTF-16（即上述的 FF FE 41 00 42 00 43 00）。 你可以打开记事本，写上ABC，然后保存，再用二进制编辑器看看它的编码结果。</p>
<p><br />
另外，UTF-16还能表示一部分的UCS-4代码点——U+10000～U+10FFFF。 表示算法比较复杂，简单说明如下：<br />
从代码点U中减去0x10000，得到U'。这样U+10000～U+10FFFF就变成了 0x00000～0xFFFFF。<br />
用20位二进制数表示U'。 U'=yyyyyyyyyyxxxxxxxxxx<br />
将前10位和后10位用W1和W2表示，W1=110110yyyyyyyyyy，W2=110111xxxxxxxxxx，则 W1 = D800～DBFF，W2 = DC00～DFFF。</p>
<p>例如，U+12345表示为 D8 08 DF 45（UTF-16BE），或者08 D8 45 DF（UTF-16LE）。</p>
<p>但是由于这种算法的存在，造成UCS-2中的 U+D800～U+DFFF 变成了无定义的字符。<br />
UTF-32</p>
<p>UTF-32用四个字节表示代码点，这样就可以完全表示UCS-4的所有代码点，而无需像UTF-16那样使用复杂的算法。 与UTF-16类似，UTF-32也包括UTF-32、UTF-32BE、UTF-32LE三种编码，UTF-32也同样需要BOM字符。 仅用'ABC'举例：UTF-32BE&nbsp;00 00 00 41 00 00 00 42 00 00 00 43<br />
UTF-32LE&nbsp;41 00 00 00 42 00 00 00 43 00 00 00<br />
UTF-32(Big Endian)&nbsp;00 00 FE FF 00 00 00 41 00 00 00 42 00 00 00 43<br />
UTF-32(Little Endian)&nbsp;FF FE 00 00 41 00 00 00 42 00 00 00 43 00 00 00<br />
UTF-32(不带BOM)&nbsp;00 00 00 41 00 00 00 42 00 00 00 43</p>
<p>UTF-8</p>
<p>UTF-16和UTF-32的一个缺点就是它们固定使用两个或四个字节， 这样在表示纯ASCII文件时会有很多00字节，造成浪费。 而RFC3629定义的UTF-8则解决了这个问题。</p>
<p>UTF-8用1～4个字节来表示代码点。表示方式如下：UCS-2 (UCS-4)&nbsp;位序列&nbsp;第一字节&nbsp;第二字节&nbsp;第三字节&nbsp;第四字节<br />
U+0000 .. U+007F&nbsp;00000000-0xxxxxxx&nbsp;0xxxxxxx&nbsp;&nbsp;&nbsp;<br />
U+0080 .. U+07FF&nbsp;00000xxx-xxyyyyyy&nbsp;110xxxxx&nbsp;10yyyyyy&nbsp;&nbsp;<br />
U+0800 .. U+FFFF&nbsp;xxxxyyyy-yyzzzzzz&nbsp;1110xxxx&nbsp;10yyyyyy&nbsp;10zzzzzz&nbsp;<br />
U+10000..U+10FFFF&nbsp;00000000-000wwwxx-<br />
xxxxyyyy-yyzzzzzzz&nbsp;11110www&nbsp;10xxxxxx&nbsp;10yyyyyy&nbsp;10zzzzzz</p>
<p><br />
可见，ASCII字符（U+0000～U+007F）部分完全使用一个字节，避免了存储空间的浪费。 而且UTF-8不再需要BOM字节。</p>
<p>另外，从上表中可以看出，单字节编码的第一字节为[00-7F]，双字节编码的第一字节为[C2-DF]， 三字节编码的第一字节为[E0-EF]。这样只要看到第一个字节的范围就可以知道编码的字节数。 这样也可以大大简化算法。</font></p>
<img src ="http://www.blogjava.net/lihao336/aggbug/306954.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2009-12-22 23:19 <a href="http://www.blogjava.net/lihao336/archive/2009/12/22/306954.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java远程通讯可选技术及原理 </title><link>http://www.blogjava.net/lihao336/archive/2009/12/13/305773.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Sun, 13 Dec 2009 04:12:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2009/12/13/305773.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/305773.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2009/12/13/305773.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/305773.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/305773.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2009/12/13/305773.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/305773.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2009-12-13 12:12 <a href="http://www.blogjava.net/lihao336/archive/2009/12/13/305773.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>理解ThreadLocal变量</title><link>http://www.blogjava.net/lihao336/archive/2009/09/23/296191.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Wed, 23 Sep 2009 09:15:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2009/09/23/296191.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/296191.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2009/09/23/296191.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/296191.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/296191.html</trackback:ping><description><![CDATA[<div style="layout-grid:  15.6pt none">
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-weight: bold; font-size: 10.5pt; font-family: 'Times New Roman'"><font face="Times New Roman"></font></span>&nbsp;</p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">概述</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">我们知道<font face="Times New Roman">Spring</font><font face="SimSun">通过各种</font><font face="Times New Roman">DAO</font><font face="SimSun">模板类降低了开发者使用各种数据持久技术的难度。这些模板类都是线程安全的，也就是说，多个</font><font face="Times New Roman">DAO</font><font face="SimSun">可以复用同一个模板实例而不会发生冲突。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">我们使用模板类访问底层数据，根据持久化技术的不同，模板类需要绑定数据连接或会话的资源。但这些资源本身是非线程安全的，也就是说它们不能在同一时刻被多个线程共享。</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">虽然模板类通过资源池获取数据连接或会话，但资源池本身解决的是数据连接或会话的缓存问题，并非数据连接或会话的线程安全问题。</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">按照传统经验，如果某个对象是非线程安全的，在多线程环境下，对对象的访问必须采用<font face="Times New Roman">synchronized</font><font face="SimSun">进行线程同步。但</font><font face="Times New Roman">Spring</font><font face="SimSun">的</font><font face="Times New Roman">DAO</font><font face="SimSun">模板类并未采用线程同步机制，因为线程同步限制了并发访问，会带来很大的性能损失。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">此外，通过代码同步解决性能安全问题挑战性很大，可能会增强好几倍的实现难度。那模板类究竟仰丈何种魔法神功，可以在无需同步的情况下就化解线程安全的难题呢？答案就是<font face="Times New Roman">ThreadLocal</font><font face="SimSun">！</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">ThreadLocal<font face="SimSun">在</font><font face="Times New Roman">Spring</font><font face="SimSun">中发挥着重要的作用，在管理</font><font face="Times New Roman">request</font><font face="SimSun">作用域的</font><font face="Times New Roman">Bean</font><font face="SimSun">、事务管理、任务调度、</font><font face="Times New Roman">AOP</font><font face="SimSun">等模块都出现了它们的身影，起着举足轻重的作用。要想了解</font><font face="Times New Roman">Spring</font><font face="SimSun">事务管理的底层技术，</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">是必须攻克的山头堡垒。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">ThreadLocal<font face="SimSun">是什么</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">早在<font face="Times New Roman">JDK&nbsp;1.2</font><font face="SimSun">的版本中就提供</font><font face="Times New Roman">java.lang.ThreadLocal</font><font face="SimSun">，</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">ThreadLocal<font face="SimSun">很容易让人望文生义，想当然地认为是一个</font><font face="Times New Roman">&#8220;</font><font face="SimSun">本地线程</font><font face="Times New Roman">&#8221;</font><font face="SimSun">。其实，</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">并不是一个</font><font face="Times New Roman">Thread</font><font face="SimSun">，而是</font><font face="Times New Roman">Thread</font><font face="SimSun">的局部变量，也许把它命名为</font><font face="Times New Roman">ThreadLocalVariable</font><font face="SimSun">更容易让人理解一些。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">当使用<font face="Times New Roman">ThreadLocal</font><font face="SimSun">维护变量时，</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">为每个使用该变量的线程提供独立的变量副本，所以每一个线程都可以独立地改变自己的副本，而不会影响其它线程所对应的副本。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">从线程的角度看，目标变量就象是线程的本地变量，这也是类名中<font face="Times New Roman">&#8220;Local&#8221;</font><font face="SimSun">所要表达的意思。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">线程局部变量并不是<font face="Times New Roman">Java</font><font face="SimSun">的新发明，很多语言（如</font><font face="Times New Roman">IBM&nbsp;IBM&nbsp;XL&nbsp;FORTRAN</font><font face="SimSun">）在语法层面就提供线程局部变量。在</font><font face="Times New Roman">Java</font><font face="SimSun">中没有提供在语言级支持，而是变相地通过</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">的类提供支持。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">所以，在<font face="Times New Roman">Java</font><font face="SimSun">中编写线程局部变量的代码相对来说要笨拙一些，因此造成线程局部变量没有在</font><font face="Times New Roman">Java</font><font face="SimSun">开发者中得到很好的普及。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">ThreadLocal<font face="SimSun">的接口方法</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">ThreadLocal<font face="SimSun">类接口很简单，只有</font><font face="Times New Roman">4</font><font face="SimSun">个方法，我们先来了解一下：</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">void&nbsp;set(Object&nbsp;value)&nbsp;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">设置当前线程的线程局部变量的值。</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;Object&nbsp;get()&nbsp;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">该方法返回当前线程所对应的线程局部变量。</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;void&nbsp;remove()&nbsp;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">将当前线程局部变量的值删除，目的是为了减少内存的占用，该方法是<font face="Times New Roman">JDK&nbsp;5.0</font><font face="SimSun">新增的方法。需要指出的是，当线程结束后，对应该线程的局部变量将自动被垃圾回收，所以显式调用该方法清除线程的局部变量并不是必须的操作，但它可以加快内存回收的速度。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">protected&nbsp;Object&nbsp;initialValue()&nbsp;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">返回该线程局部变量的初始值，该方法是一个<font face="Times New Roman">protected</font><font face="SimSun">的方法，显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法，在线程第</font><font face="Times New Roman">1</font><font face="SimSun">次调用</font><font face="Times New Roman">get()</font><font face="SimSun">或</font><font face="Times New Roman">set(Object)</font><font face="SimSun">时才执行，并且仅执行</font><font face="Times New Roman">1</font><font face="SimSun">次。</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">中的缺省实现直接返回一个</font><font face="Times New Roman">null</font><font face="SimSun">。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">值得一提的是，在<font face="Times New Roman">JDK5.0</font><font face="SimSun">中，</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">已经支持泛型，该类的类名已经变为</font><font face="Times New Roman">ThreadLocal&lt;T&gt;</font><font face="SimSun">。</font><font face="Times New Roman">API</font><font face="SimSun">方法也相应进行了调整，新版本的</font><font face="Times New Roman">API</font><font face="SimSun">方法分别是</font><font face="Times New Roman">void&nbsp;set(T&nbsp;value)</font><font face="SimSun">、</font><font face="Times New Roman">T&nbsp;get()</font><font face="SimSun">以及</font><font face="Times New Roman">T&nbsp;initialValue()</font><font face="SimSun">。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">ThreadLocal<font face="SimSun">是如何做到为每一个线程维护变量的副本的呢？其实实现的思路很简单：在</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">类中有一个</font><font face="Times New Roman">Map</font><font face="SimSun">，用于存储每一个线程的变量副本，</font><font face="Times New Roman">Map</font><font face="SimSun">中元素的键为线程对象，而值对应线程的变量副本。我们自己就可以提供一个简单的实现版本：</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">代码清单<font face="Times New Roman">1&nbsp;SimpleThreadLocal</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;class&nbsp;SimpleThreadLocal&nbsp;{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">private&nbsp;Map&nbsp;valueMap&nbsp;=&nbsp;Collections.synchronizedMap(new&nbsp;HashMap());</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;void&nbsp;set(Object&nbsp;newValue)&nbsp;{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">valueMap.put(Thread.currentThread(),&nbsp;newValue);①<font face="SimSun">键为线程对象，值为本线程的变量副本</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;Object&nbsp;get()&nbsp;{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">Thread&nbsp;currentThread&nbsp;=&nbsp;Thread.currentThread();</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">Object&nbsp;o&nbsp;=&nbsp;valueMap.get(currentThread);②<font face="SimSun">返回本线程对应的变量</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">if&nbsp;(o&nbsp;==&nbsp;null&nbsp;&amp;&amp;&nbsp;!valueMap.containsKey(currentThread))&nbsp;{③<font face="SimSun">如果在</font><font face="Times New Roman">Map</font><font face="SimSun">中不存在，放到</font><font face="Times New Roman">Map</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">中保存起来。</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">o&nbsp;=&nbsp;initialValue();</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">valueMap.put(currentThread,&nbsp;o);</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">return&nbsp;o;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;void&nbsp;remove()&nbsp;{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">valueMap.remove(Thread.currentThread());</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;Object&nbsp;initialValue()&nbsp;{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">return&nbsp;null;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">虽然代码清单<font face="Times New Roman">9‑3</font><font face="SimSun">这个</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">实现版本显得比较幼稚，但它和</font><font face="Times New Roman">JDK</font><font face="SimSun">所提供的</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">类在实现思路上是相近的。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">一个<font face="Times New Roman">TheadLocal</font><font face="SimSun">实例</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">下面，我们通过一个具体的实例了解一下<font face="Times New Roman">ThreadLocal</font><font face="SimSun">的具体使用方法。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">代码清单<font face="Times New Roman">2&nbsp;SequenceNumber</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">package&nbsp;com.baobaotao.basic;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;class&nbsp;SequenceNumber&nbsp;{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">①<font face="SimSun">通过匿名内部类覆盖</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">的</font><font face="Times New Roman">initialValue()</font><font face="SimSun">方法，指定初始值</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">private&nbsp;static&nbsp;ThreadLocal&lt;Integer&gt;&nbsp;seqNum&nbsp;=&nbsp;new&nbsp;ThreadLocal&lt;Integer&gt;(){</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;Integer&nbsp;initialValue(){</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">return&nbsp;0;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">};</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">②<font face="SimSun">获取下一个序列值</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;int&nbsp;getNextNum(){</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">seqNum.set(seqNum.get()+1);</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">return&nbsp;seqNum.get();</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">SequenceNumber&nbsp;sn&nbsp;=&nbsp;new&nbsp;SequenceNumber();</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">③&nbsp;3<font face="SimSun">个线程共享</font><font face="Times New Roman">sn</font><font face="SimSun">，各自产生序列号</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">TestClient&nbsp;t1&nbsp;=&nbsp;new&nbsp;TestClient(sn);</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">TestClient&nbsp;t2&nbsp;=&nbsp;new&nbsp;TestClient(sn);</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">TestClient&nbsp;t3&nbsp;=&nbsp;new&nbsp;TestClient(sn);</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">t1.start();</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">t2.start();</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">t3.start();</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">private&nbsp;static&nbsp;class&nbsp;TestClient&nbsp;extends&nbsp;Thread</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">private&nbsp;SequenceNumber&nbsp;sn;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;TestClient(SequenceNumber&nbsp;sn)&nbsp;{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">this.sn&nbsp;=&nbsp;sn;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;void&nbsp;run()</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;3;&nbsp;i++)&nbsp;{④<font face="SimSun">每个线程打出</font><font face="Times New Roman">3</font><font face="SimSun">个序列值</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">System.out.println("thread["+Thread.currentThread().getName()+</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">"]&nbsp;sn["+sn.getNextNum()+"]");</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">&nbsp;&nbsp;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">通常我们通过匿名内部类的方式定义<font face="Times New Roman">ThreadLocal</font><font face="SimSun">的子类，提供初始的变量值，如例子中</font><font face="Times New Roman">①</font><font face="SimSun">处所示。</font><font face="Times New Roman">TestClient</font><font face="SimSun">线程产生一组序列号，在</font><font face="Times New Roman">③</font><font face="SimSun">处，我们生成</font><font face="Times New Roman">3</font><font face="SimSun">个</font><font face="Times New Roman">TestClient</font><font face="SimSun">，它们共享同一个</font><font face="Times New Roman">SequenceNumber</font><font face="SimSun">实例。运行以上代码，在控制台上输出以下的结果：</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">thread[Thread-2]&nbsp;sn[1]</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">thread[Thread-0]&nbsp;sn[1]</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">thread[Thread-1]&nbsp;sn[1]</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">thread[Thread-2]&nbsp;sn[2]</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">thread[Thread-0]&nbsp;sn[2]</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">thread[Thread-1]&nbsp;sn[2]</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">thread[Thread-2]&nbsp;sn[3]</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">thread[Thread-0]&nbsp;sn[3]</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">thread[Thread-1]&nbsp;sn[3]</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">考察输出的结果信息，我们发现每个线程所产生的序号虽然都共享同一个<font face="Times New Roman">SequenceNumber</font><font face="SimSun">实例，但它们并没有发生相互干扰的情况，而是各自产生独立的序列号，这是因为我们通过</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">为每一个线程提供了单独的副本。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">Thread<font face="SimSun">同步机制的比较</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">ThreadLocal<font face="SimSun">和线程同步机制相比有什么优势呢？</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">在同步机制中，通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的，使用同步机制要求程序慎密地分析什么时候对变量进行读写，什么时候需要锁定某个对象，什么时候释放对象锁等繁杂的问题，程序设计和编写难度相对较大。</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">而<font face="Times New Roman">ThreadLocal</font><font face="SimSun">则从另一个角度来解决多线程的并发访问。</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">会为每一个线程提供一个独立的变量副本，从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本，从而也就没有必要对该变量进行同步了。</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">提供了线程安全的共享对象，在编写多线程代码时，可以把不安全的变量封装进</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">由于<font face="Times New Roman">ThreadLocal</font><font face="SimSun">中可以持有任何类型的对象，低版本</font><font face="Times New Roman">JDK</font><font face="SimSun">所提供的</font><font face="Times New Roman">get()</font><font face="SimSun">返回的是</font><font face="Times New Roman">Object</font><font face="SimSun">对象，需要强制类型转换。但</font><font face="Times New Roman">JDK&nbsp;5.0</font><font face="SimSun">通过泛型很好的解决了这个问题，在一定程度地简化</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">的使用，代码清单&nbsp;</font><font face="Times New Roman">9&nbsp;2</font><font face="SimSun">就使用了</font><font face="Times New Roman">JDK&nbsp;5.0</font><font face="SimSun">新的</font><font face="Times New Roman">ThreadLocal&lt;T&gt;</font><font face="SimSun">版本。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">概括起来说，对于多线程资源共享的问题，同步机制采用了<font face="Times New Roman">&#8220;</font><font face="SimSun">以时间换空间</font><font face="Times New Roman">&#8221;</font><font face="SimSun">的方式，而</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">采用了</font><font face="Times New Roman">&#8220;</font><font face="SimSun">以空间换时间</font><font face="Times New Roman">&#8221;</font><font face="SimSun">的方式。前者仅提供一份变量，让不同的线程排队访问，而后者为每一个线程都提供了一份变量，因此可以同时访问而互不影响。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">Spring<font face="SimSun">使用</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">解决线程安全问题</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">我们知道在一般情况下，只有无状态的<font face="Times New Roman">Bean</font><font face="SimSun">才可以在多线程环境下共享，在</font><font face="Times New Roman">Spring</font><font face="SimSun">中，绝大部分</font><font face="Times New Roman">Bean</font><font face="SimSun">都可以声明为</font><font face="Times New Roman">singleton</font><font face="SimSun">作用域。就是因为</font><font face="Times New Roman">Spring</font><font face="SimSun">对一些</font><font face="Times New Roman">Bean</font><font face="SimSun">（如</font><font face="Times New Roman">RequestContextHolder</font><font face="SimSun">、</font><font face="Times New Roman">TransactionSynchronizationManager</font><font face="SimSun">、</font><font face="Times New Roman">LocaleContextHolder</font><font face="SimSun">等）中非线程安全状态采用</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">进行处理，让它们也成为线程安全的状态，因为有状态的</font><font face="Times New Roman">Bean</font><font face="SimSun">就可以在多线程中共享了。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">一般的<font face="Times New Roman">Web</font><font face="SimSun">应用划分为展现层、服务层和持久层三个层次，在不同的层中编写对应的逻辑，下层通过接口向上层开放功能调用。在一般情况下，从接收请求到返回响应所经过的所有程序调用都同属于一个线程，如图</font><font face="Times New Roman">9‑2</font><font face="SimSun">所示：</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><img height="247" alt="" src="file:///C:/DOCUME~1/lihao/LOCALS~1/Temp/ksohtml/wps_clip_image-4948.png" width="432" /></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-align: center"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">图<font face="Times New Roman">1</font><font face="SimSun">同一线程贯通三层</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">这样你就可以根据需要，将一些非线程安全的变量以<font face="Times New Roman">ThreadLocal</font><font face="SimSun">存放，在同一次请求响应的调用线程中，所有关联的对象引用到的都是同一个变量。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">下面的实例能够体现<font face="Times New Roman">Spring</font><font face="SimSun">对有状态</font><font face="Times New Roman">Bean</font><font face="SimSun">的改造思路：</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">代码清单<font face="Times New Roman">3&nbsp;TopicDao</font><font face="SimSun">：非线程安全</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;class&nbsp;TopicDao&nbsp;{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">private&nbsp;Connection&nbsp;conn;①<font face="SimSun">一个非线程安全的变量</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;void&nbsp;addTopic(){</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">Statement&nbsp;stat&nbsp;=&nbsp;conn.createStatement();②<font face="SimSun">引用非线程安全变量</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">&#8230;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">由于<font face="Times New Roman">①</font><font face="SimSun">处的</font><font face="Times New Roman">conn</font><font face="SimSun">是成员变量，因为</font><font face="Times New Roman">addTopic()</font><font face="SimSun">方法是非线程安全的，必须在使用时创建一个新</font><font face="Times New Roman">TopicDao</font><font face="SimSun">实例（非</font><font face="Times New Roman">singleton</font><font face="SimSun">）。下面使用</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">对</font><font face="Times New Roman">conn</font><font face="SimSun">这个非线程安全的</font><font face="Times New Roman">&#8220;</font><font face="SimSun">状态</font><font face="Times New Roman">&#8221;</font><font face="SimSun">进行改造：</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">代码清单<font face="Times New Roman">4&nbsp;TopicDao</font><font face="SimSun">：线程安全</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">import&nbsp;java.sql.Connection;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">import&nbsp;java.sql.Statement;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;class&nbsp;TopicDao&nbsp;{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">①<font face="SimSun">使用</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">保存</font><font face="Times New Roman">Connection</font><font face="SimSun">变量</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">private&nbsp;static&nbsp;ThreadLocal&lt;Connection&gt;&nbsp;connThreadLocal&nbsp;=&nbsp;new&nbsp;ThreadLocal&lt;Connection&gt;();</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;static&nbsp;Connection&nbsp;getConnection(){</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">②<font face="SimSun">如果</font><font face="Times New Roman">connThreadLocal</font><font face="SimSun">没有本线程对应的</font><font face="Times New Roman">Connection</font><font face="SimSun">创建一个新的</font><font face="Times New Roman">Connection</font><font face="SimSun">，</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">并将其保存到线程本地变量中。</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">if&nbsp;(connThreadLocal.get()&nbsp;==&nbsp;null)&nbsp;{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">Connection&nbsp;conn&nbsp;=&nbsp;ConnectionManager.getConnection();</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">connThreadLocal.set(conn);</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">return&nbsp;conn;</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}else{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">return&nbsp;connThreadLocal.get();③<font face="SimSun">直接返回线程本地变量</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">public&nbsp;void&nbsp;addTopic()&nbsp;{</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">④<font face="SimSun">从</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">中获取线程对应的</font><font face="Times New Roman">Connection</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">Statement&nbsp;stat&nbsp;=&nbsp;getConnection().createStatement();</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">}</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">不同的线程在使用<font face="Times New Roman">TopicDao</font><font face="SimSun">时，先判断</font><font face="Times New Roman">connThreadLocal.get()</font><font face="SimSun">是否是</font><font face="Times New Roman">null</font><font face="SimSun">，如果是</font><font face="Times New Roman">null</font><font face="SimSun">，则说明当前线程还没有对应的</font><font face="Times New Roman">Connection</font><font face="SimSun">对象，这时创建一个</font><font face="Times New Roman">Connection</font><font face="SimSun">对象并添加到本地线程变量中；如果不为</font><font face="Times New Roman">null</font><font face="SimSun">，则说明当前的线程已经拥有了</font><font face="Times New Roman">Connection</font><font face="SimSun">对象，直接使用就可以了。这样，就保证了不同的线程使用线程相关的</font><font face="Times New Roman">Connection</font><font face="SimSun">，而不会使用其它线程的</font><font face="Times New Roman">Connection</font><font face="SimSun">。因此，这个</font><font face="Times New Roman">TopicDao</font><font face="SimSun">就可以做到</font><font face="Times New Roman">singleton</font><font face="SimSun">共享了。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">当然，这个例子本身很粗糙，将<font face="Times New Roman">Connection</font><font face="SimSun">的</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">直接放在</font><font face="Times New Roman">DAO</font><font face="SimSun">只能做到本</font><font face="Times New Roman">DAO</font><font face="SimSun">的多个方法共享</font><font face="Times New Roman">Connection</font><font face="SimSun">时不发生线程安全问题，但无法和其它</font><font face="Times New Roman">DAO</font><font face="SimSun">共用同一个</font><font face="Times New Roman">Connection</font><font face="SimSun">，要做到同一事务多</font><font face="Times New Roman">DAO</font><font face="SimSun">共享同一</font><font face="Times New Roman">Connection</font><font face="SimSun">，必须在一个共同的外部类使用</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">保存</font><font face="Times New Roman">Connection</font><font face="SimSun">。但这个实例基本上说明了</font><font face="Times New Roman">Spring</font><font face="SimSun">对有状态类线程安全化的解决思路。</font></span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">小结</span></p>
<p style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'">ThreadLocal<font face="SimSun">是解决线程安全问题一个很好的思路，它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下，</font><font face="Times New Roman">ThreadLocal</font><font face="SimSun">比直接使用</font><font face="Times New Roman">synchronized</font><font face="SimSun">同步机制解决线程安全问题更简单，更方便，且结果程序拥有更高的并发性。</font></span></p>
<br />
<br />
原文出处：http://www.builder.com.cn/2007/0529/404698.shtml</div>
<img src ="http://www.blogjava.net/lihao336/aggbug/296191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2009-09-23 17:15 <a href="http://www.blogjava.net/lihao336/archive/2009/09/23/296191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>常用log4j.properties</title><link>http://www.blogjava.net/lihao336/archive/2009/09/22/296039.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Tue, 22 Sep 2009 07:58:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2009/09/22/296039.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/296039.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2009/09/22/296039.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/296039.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/296039.html</trackback:ping><description><![CDATA[<p>log4j.rootLogger=DEBUG,CONSOLE,DATABASE,FILE<br />
log4j.addivity.org.apache=true</p>
<p># 应用于控制台<br />
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender<br />
log4j.appender.CONSOLE.Threshold=INFO<br />
log4j.appender.CONSOLE.Target=System.out<br />
log4j.appender.CONSOLE.Encoding=GBK<br />
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout<br />
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</p>
<p># 用于数据库<br />
#log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender<br />
#log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/ww<br />
#log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver<br />
#log4j.appender.DATABASE.user=root <br />
#log4j.appender.DATABASE.password=123<br />
#log4j.appender.CONSOLE.Threshold=WARN<br />
#log4j.appender.DATABASE.sql=INSERT INTO LOG(stamp,thread, infolevel,class,messages) VALUES ('%d{yyyy-MM-dd HH:mm:ss}', '%t', '%p', '%l', '%m')<br />
# INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')<br />
# 写入数据库中的表LOG的Message字段中，内容％d（日期）%c: 日志信息所在地（类名）%p: 日志信息级别%m: 产生的日志具体信息 %n: 输出日志信息换行<br />
#log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout<br />
#log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</p>
<p># 每天新建日志<br />
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender<br />
log4j.appender.A1.File=C:/log4j/log<br />
log4j.appender.A1.Encoding=GBK<br />
log4j.appender.A1.Threshold=DEBUG<br />
log4j.appender.A1.DatePattern='.'yyyy-MM-dd<br />
log4j.appender.A1.layout=org.apache.log4j.PatternLayout<br />
log4j.appender.A1.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L : %m%n</p>
<p>#应用于文件<br />
log4j.appender.FILE=org.apache.log4j.FileAppender<br />
log4j.appender.FILE.File=C:/log4j/file.log<br />
log4j.appender.FILE.Append=false<br />
log4j.appender.FILE.Encoding=GBK<br />
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout<br />
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</p>
<p># 应用于文件回滚<br />
log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender<br />
log4j.appender.ROLLING_FILE.Threshold=ERROR<br />
log4j.appender.ROLLING_FILE.File=rolling.log<br />
log4j.appender.ROLLING_FILE.Append=true<br />
log4j.appender.CONSOLE_FILE.Encoding=GBK<br />
log4j.appender.ROLLING_FILE.MaxFileSize=10KB<br />
log4j.appender.ROLLING_FILE.MaxBackupIndex=1<br />
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout<br />
log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</p>
<p>#自定义Appender<br />
log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender<br />
log4j.appender.im.host = mail.cybercorlin.net<br />
log4j.appender.im.username = username<br />
log4j.appender.im.password = password<br />
log4j.appender.im.recipient = corlin@cybercorlin.net<br />
log4j.appender.im.layout=org.apache.log4j.PatternLayout<br />
log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</p>
<p>#应用于socket<br />
log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender<br />
log4j.appender.SOCKET.RemoteHost=localhost<br />
log4j.appender.SOCKET.Port=5001<br />
log4j.appender.SOCKET.LocationInfo=true<br />
# Set up for Log Facter 5<br />
log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout<br />
log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n<br />
# Log Factor 5 Appender<br />
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender<br />
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000</p>
<p># 发送日志给邮件<br />
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender<br />
log4j.appender.MAIL.Threshold=FATAL<br />
log4j.appender.MAIL.BufferSize=10<br />
<a href="mailto:log4j.appender.MAIL.From=user@abc.com">log4j.appender.MAIL.From=user@abc.com</a><br />
log4j.appender.MAIL.SMTPHost=www.abc.com<br />
log4j.appender.MAIL.Subject=Log4J Message<br />
<a href="mailto:log4j.appender.MAIL.To=user@abc.com">log4j.appender.MAIL.To=user@abc.com</a><br />
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout<br />
log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</p>
<br />
<br />
参考资料：<br />
<a title="log4j详解与实战" href="http://www.javaeye.com/topic/378077">log4j详解与实战</a>
<img src ="http://www.blogjava.net/lihao336/aggbug/296039.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2009-09-22 15:58 <a href="http://www.blogjava.net/lihao336/archive/2009/09/22/296039.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>参考资源</title><link>http://www.blogjava.net/lihao336/archive/2009/09/21/295887.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Mon, 21 Sep 2009 09:19:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2009/09/21/295887.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/295887.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2009/09/21/295887.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/295887.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/295887.html</trackback:ping><description><![CDATA[<h1>&nbsp;</h1>
<p><span style="color: red">1.理解DOM——很详尽的DOM入门资料</span><br />
<a href="https://www6.software.ibm.com/developerworks/cn/education/xml/x-udom/section2.html"><strong>https://www6.software.ibm.com/developerworks/cn/education/xml/x-udom/section2.html</strong></a><br />
<br />
<a href="http://www.cnblogs.com/huangyu/articles/33572.html"><strong>http://www.cnblogs.com/huangyu/articles/33572.html</strong></a><br />
<img height="400" alt="DOM路标图" src="http://images.cnblogs.com/cnblogs_com/huangyu/roadmap.gif" width="400" border="0" /><br />
DOM路标图<br />
</p>
<p style="color: #ff0000"><br />
2.理解SAX</p>
<p><a href="https://www6.software.ibm.com/developerworks/cn/education/xml/x-usax/index.html"><strong>https://www6.software.ibm.com/developerworks/cn/education/xml/x-usax/index.html</strong></a><br />
<br />
<a href="http://www.cnblogs.com/huangyu/archive/2004/08/16/33934.html"><strong>http://www.cnblogs.com/huangyu/archive/2004/08/16/33934.html</strong></a><br />
<a name="N10129"><span class="smalltitle"><br />
<br />
SAX 是什么？</span></a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;用于读取和操作 XML 文件的标准是文档对象模型（Document Object Model，DOM）。遗憾的是，DOM 方法涉及读取整个文件并将该文件存储在一个树结构中，而这样可能是低效的、缓慢的，并且很消耗资源。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;一种替代技术就是 Simple API for XML，或称为 SAX。SAX 允许您在读取文档时处理它，从而不必等待整个文档被存储之后才采取操作。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;SAX 是由 XML-DEV 邮件列表的成员开发的，现在对应的 Java 版本是 SourceForge 项目（请参阅 <a href="https://www6.software.ibm.com/developerworks/cn/education/xml/x-usax/resources.html" cmimpressionsent="1">参考资料</a>）。该项目的目的是为 XML 的使用提供一种更自然的手段 —— 换句话说，也就是不涉及 DOM 所必需的开销和概念跳跃。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;项目的成果是一个<em>基于事件</em> 的 API。解析器向一个事件处理程序发送事件，比如元素的开始和结束，而事件处理程序则处理该信息。然后应用程序才能够处理该数据。原始的文档仍然保持原样，但是 SAX 提供了操作数据的手段，因此数据可以用于另一个进程或文档。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;SAX 没有官方的标准机构，由万维网联盟（Wide Web Consortium，W3C）或其他官方机构维护，但它是 XML 社区事实上的标准。</p>
<p>SAX 处理涉及以下步骤：</p>
<ol>
    <li>创建一个事件处理程序。
    </li>
    <li>创建 SAX 解析器。
    </li>
    <li>向解析器分配事件处理程序。
    </li>
    <li>解析文档，同时向事件处理程序发送每个事件。 </li>
</ol>
<p><a name="N1018D"><span class="smalltitle">基于事件的处理的优点和缺点</span></a></p>
<p>这种处理的优点非常类似于流媒体的优点。分析能够立即开始，而不是等待所有的数据被处理。而且，由于应用程序只是在读取数据时检查数据，因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上，应用程序甚至不必解析整个文档；它可以在某个条件得到满足时停止解析。一般来说，SAX 还比它的替代者 DOM 快许多。</p>
<p>另一方面，<span style="color: #ff0000">由于应用程序没有以任何方式存储数据，使用 SAX 来更改数据或在数据流中往后移是不可能的。</span><br />
<br />
SAX 和 DOM 不是相互排斥的，记住这点很重要。您可以使用 DOM 来创建 SAX 事件流，也可以使用 SAX 来创建 DOM 树。事实上，用于创建 DOM 树的大多数解析器实际上都使用 SAX 来完成这个任务！<br />
<br />
3.DW上的相关资源<br />
<a href="http://www.ibm.com/developerworks/cn/xml/"><strong>http://www.ibm.com/developerworks/cn/xml/</strong></a><br />
<br />
<br />
4.使用Xpath提高基于DOM的XML处理效率<br />
<a href="http://www.ibm.com/developerworks/cn/xml/x-domjava/index.shtml"><strong>http://www.ibm.com/developerworks/cn/xml/x-domjava/index.shtml</strong></a> <br />
</p>
<img src ="http://www.blogjava.net/lihao336/aggbug/295887.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2009-09-21 17:19 <a href="http://www.blogjava.net/lihao336/archive/2009/09/21/295887.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于REST</title><link>http://www.blogjava.net/lihao336/archive/2009/09/17/295494.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Thu, 17 Sep 2009 12:06:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2009/09/17/295494.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/295494.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2009/09/17/295494.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/295494.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/295494.html</trackback:ping><description><![CDATA[<br />
<div class="Section0" style="layout-grid:  15.6pt none">
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">这阵子正打算用<font face="Times New Roman">Rails</font><font face="SimSun">做个东东，所以开始系统地学习起了</font><font face="Times New Roman">Rails</font><font face="SimSun">。巧合的是，大概两周前，</font><font face="Times New Roman">dlee</font><font face="SimSun">邀请我加入</font><font face="Times New Roman">Fielding</font><font face="SimSun">博士关于</font><font face="Times New Roman">REST</font><font face="SimSun">的那篇论文的翻译团队。可以说</font><font face="Times New Roman">Rails</font><font face="SimSun">和</font><font face="Times New Roman">REST</font><font face="SimSun">这两个最热门的词汇几乎同时挤入了我的生活。随着我对</font><font face="Times New Roman">Rails</font><font face="SimSun">的学习和对</font><font face="Times New Roman">[Fielding]</font><font face="SimSun">的翻译，我也开始对</font><font face="Times New Roman">REST</font><font face="SimSun">产生了一些不太成熟的想法，写在这里与大家分享，同时也起到抛砖引玉的作用，欢迎大家讨论。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">先复习一下<font face="Times New Roman">REST</font><font face="SimSun">的基本思想。</font><font face="Times New Roman">[Fielding]</font><font face="SimSun">把</font><font face="Times New Roman">REST</font><font face="SimSun">形式化地定义为一种架构风格（</font><font face="Times New Roman">architecture&nbsp;style</font><font face="SimSun">），它有架构元素（</font><font face="Times New Roman">element</font><font face="SimSun">）和架构约束（</font><font face="Times New Roman">constraint</font><font face="SimSun">）组成。这些概念比较晦涩难懂，而且我们做工程的往往并不需要形而上的理解。我们只知道，</font><font face="Times New Roman">REST</font><font face="SimSun">是一种针对网络应用的设计和开发方式，可以降低开发的复杂性，提高系统的可伸缩性。</font><font face="Times New Roman">REST</font><font face="SimSun">提出了一些设计概念和准则：</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">网络上的所有事物都被抽象为资源（<font face="Times New Roman">resource</font><font face="SimSun">）；&nbsp;</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">每个资源对应一个唯一的资源标识（<font face="Times New Roman">resource&nbsp;identifier</font><font face="SimSun">）；&nbsp;</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">通过通用的连接器接口（<font face="Times New Roman">generic&nbsp;connector&nbsp;interface</font><font face="SimSun">）对资源进行操作；&nbsp;</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">对资源的各种操作不会改变资源标识；&nbsp;</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">所有的操作都是无状态的（<font face="Times New Roman">stateless</font><font face="SimSun">）。&nbsp;</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">对于当今最常见的网络应用来说，<font face="Times New Roman">resource&nbsp;identifier</font><font face="SimSun">是</font><font face="Times New Roman">url</font><font face="SimSun">，</font><font face="Times New Roman">generic&nbsp;connector&nbsp;interface</font><font face="SimSun">是</font><font face="Times New Roman">HTTP</font><font face="SimSun">，第</font><font face="Times New Roman">4</font><font face="SimSun">条准则就是我们常说的</font><font face="Times New Roman">url</font><font face="SimSun">不变性。这些概念中的</font><font face="Times New Roman">resouce</font><font face="SimSun">最容易使人产生误解。</font><font face="Times New Roman">resouce</font><font face="SimSun">所指的并不是数据，而是数据</font><font face="Times New Roman">+</font><font face="SimSun">特定的表现形式（</font><font face="Times New Roman">representation</font><font face="SimSun">），这也是为什么</font><font face="Times New Roman">REST</font><font face="SimSun">的全名是</font><font face="Times New Roman">Representational&nbsp;State&nbsp;Transfer</font><font face="SimSun">的原因。举个例子来说，</font><font face="Times New Roman">&#8220;</font><font face="SimSun">本月卖得最好的</font><font face="Times New Roman">10</font><font face="SimSun">本书</font><font face="Times New Roman">&#8221;</font><font face="SimSun">和</font><font face="Times New Roman">&#8220;</font><font face="SimSun">你最喜欢的</font><font face="Times New Roman">10</font><font face="SimSun">本书</font><font face="Times New Roman">&#8221;</font><font face="SimSun">在数据上可能有重叠（有一本书即卖得好，你又喜欢），甚至完全相同。但是它们的</font><font face="Times New Roman">representation</font><font face="SimSun">不同，因此是不同的</font><font face="Times New Roman">resource</font><font face="SimSun">。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">REST<font face="SimSun">之所以能够简化开发，是因为其引入的架构约束，比如</font><font face="Times New Roman">Rails&nbsp;1.2</font><font face="SimSun">中对</font><font face="Times New Roman">REST</font><font face="SimSun">的实现默认把</font><font face="Times New Roman">controller</font><font face="SimSun">中的方法限制在</font><font face="Times New Roman">7</font><font face="SimSun">个：</font><font face="Times New Roman">index</font><font face="SimSun">、</font><font face="Times New Roman">show</font><font face="SimSun">、</font><font face="Times New Roman">new</font><font face="SimSun">、</font><font face="Times New Roman">edit</font><font face="SimSun">、</font><font face="Times New Roman">create</font><font face="SimSun">、</font><font face="Times New Roman">update</font><font face="SimSun">和</font><font face="Times New Roman">destory</font><font face="SimSun">，这实际上就是对</font><font face="Times New Roman">CURD</font><font face="SimSun">的实现。更进一步讲，</font><font face="Times New Roman">Rails</font><font face="SimSun">（也是当今大部分网络应用）使用</font><font face="Times New Roman">HTTP</font><font face="SimSun">作为</font><font face="Times New Roman">generic&nbsp;connector&nbsp;interface</font><font face="SimSun">，</font><font face="Times New Roman">HTTP</font><font face="SimSun">则把对一个</font><font face="Times New Roman">url</font><font face="SimSun">的操作限制在了</font><font face="Times New Roman">4</font><font face="SimSun">个之内：</font><font face="Times New Roman">GET</font><font face="SimSun">、</font><font face="Times New Roman">POST</font><font face="SimSun">、</font><font face="Times New Roman">PUT</font><font face="SimSun">和</font><font face="Times New Roman">DELETE</font><font face="SimSun">。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">REST<font face="SimSun">之所以能够提高系统的可伸缩性，是因为它强制所有操作都是</font><font face="Times New Roman">stateless</font><font face="SimSun">的，这样就没有</font><font face="Times New Roman">context</font><font face="SimSun">的约束，如果要做分布式、做集群，就不需要考虑</font><font face="Times New Roman">context</font><font face="SimSun">的问题了。同时，它令系统可以有效地使用</font><font face="Times New Roman">pool</font><font face="SimSun">。</font><font face="Times New Roman">REST</font><font face="SimSun">对性能的另一个提升来自其对</font><font face="Times New Roman">client</font><font face="SimSun">和</font><font face="Times New Roman">server</font><font face="SimSun">任务的分配：</font><font face="Times New Roman">server</font><font face="SimSun">只负责提供</font><font face="Times New Roman">resource</font><font face="SimSun">以及操作</font><font face="Times New Roman">resource</font><font face="SimSun">的服务，而</font><font face="Times New Roman">client</font><font face="SimSun">要根据</font><font face="Times New Roman">resource</font><font face="SimSun">中的</font><font face="Times New Roman">data</font><font face="SimSun">和</font><font face="Times New Roman">representation</font><font face="SimSun">自己做</font><font face="Times New Roman">render</font><font face="SimSun">。这就减少了服务器的开销。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">既然<font face="Times New Roman">REST</font><font face="SimSun">有这样的好处，那我们应该义无反顾地拥抱它啊！目前一些大牛（像</font><font face="Times New Roman">DHH</font><font face="SimSun">）都已经开始投入到了</font><font face="Times New Roman">REST</font><font face="SimSun">的世界，那我们这些人应该做什么或者说思考写什么你呢？我觉得我们应该思考两个问题：</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">如何使用<font face="Times New Roman">REST</font><font face="SimSun">；&nbsp;</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">REST<font face="SimSun">和</font><font face="Times New Roman">MVC</font><font face="SimSun">的关系。&nbsp;</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">第一个问题假设<font face="Times New Roman">REST</font><font face="SimSun">是我们应该采用的架构，然后讨论如何使用；第二个问题则要说明</font><font face="Times New Roman">REST</font><font face="SimSun">和当前最普遍应用的</font><font face="Times New Roman">MVC</font><font face="SimSun">是什么关系，互补还是取代？</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">我们先来谈谈第一个问题，如何使用<font face="Times New Roman">REST</font><font face="SimSun">。我感觉，</font><font face="Times New Roman">REST</font><font face="SimSun">除了给我们带来了一个崭新的架构以外，还有一个重要的贡献是在开发系统过程中的一种新的思维方式：通过</font><font face="Times New Roman">url</font><font face="SimSun">来设计系统的结构。根据</font><font face="Times New Roman">REST</font><font face="SimSun">，每个</font><font face="Times New Roman">url</font><font face="SimSun">都代表一个</font><font face="Times New Roman">resource</font><font face="SimSun">，而整个系统就是由这些</font><font face="Times New Roman">resource</font><font face="SimSun">组成的。因此，如果</font><font face="Times New Roman">url</font><font face="SimSun">是设计良好的，那么系统的结构就也应该是设计良好的。对于非高手级的开发人员来说，考虑一个系统如何架构总是一个很抽象的问题。敏捷开发所提倡的</font><font face="Times New Roman">Test&nbsp;Driven&nbsp;Development</font><font face="SimSun">，其好处之一（我觉得是最大的好处）就是可以通过</font><font face="Times New Roman">testcase</font><font face="SimSun">直观地设计系统的接口。比如在还没有创建一个</font><font face="Times New Roman">class</font><font face="SimSun">的时候就编写一个</font><font face="Times New Roman">testcase</font><font face="SimSun">，虽然设置不能通过编译，但是</font><font face="Times New Roman">testcase</font><font face="SimSun">中的方法调用可以很好地从</font><font face="Times New Roman">class</font><font face="SimSun">使用者的角度反映出需要的接口，从而为</font><font face="Times New Roman">class</font><font face="SimSun">的设计提供了直观的表现。这与在</font><font face="Times New Roman">REST</font><font face="SimSun">架构中通过</font><font face="Times New Roman">url</font><font face="SimSun">设计系统结构非常类似。虽然我们连一个功能都没有实现，但是我们可以先设计出我们认为合理的</font><font face="Times New Roman">url</font><font face="SimSun">，这些</font><font face="Times New Roman">url</font><font face="SimSun">甚至不能连接到任何</font><font face="Times New Roman">page</font><font face="SimSun">或</font><font face="Times New Roman">action</font><font face="SimSun">，但是它们直观地告诉我们：系统对用户的访问接口就应该是这样。根据这些</font><font face="Times New Roman">url</font><font face="SimSun">，我们可以很方便地设计系统的结构。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">让我在这里重申一遍：<font face="Times New Roman">REST</font><font face="SimSun">允许我们通过</font><font face="Times New Roman">url</font><font face="SimSun">设计系统，就像</font><font face="Times New Roman">Test&nbsp;Driven&nbsp;Development</font><font face="SimSun">允许我们使用</font><font face="Times New Roman">testcase</font><font face="SimSun">设计</font><font face="Times New Roman">class</font><font face="SimSun">接口一样。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">OK<font face="SimSun">，既然</font><font face="Times New Roman">url</font><font face="SimSun">有这样的好处，那我们就着重讨论一下如何设计</font><font face="Times New Roman">url</font><font face="SimSun">。网络应用通常都是有</font><font face="Times New Roman">hierarchy</font><font face="SimSun">的，像棵大树。我们通常希望</font><font face="Times New Roman">url</font><font face="SimSun">也能反映出资源的层次性。比如对于一个</font><font face="Times New Roman">blog</font><font face="SimSun">应用：</font><font face="Times New Roman">/articles</font><font face="SimSun">表示所有的文章，</font><font face="Times New Roman">/articles/1</font><font face="SimSun">表示</font><font face="Times New Roman">id</font><font face="SimSun">为</font><font face="Times New Roman">1</font><font face="SimSun">的文章，这都比较直观。遗憾的是，网络应用的资源结构永远不会如此简单。因此人们常常会问这样一个问题：</font><font face="Times New Roman">RESTful</font><font face="SimSun">的</font><font face="Times New Roman">url</font><font face="SimSun">能覆盖所有的用户请求吗？比如，</font><font face="Times New Roman">login</font><font face="SimSun">如何</font><font face="Times New Roman">RESTful</font><font face="SimSun">？</font><font face="Times New Roman">search</font><font face="SimSun">如何</font><font face="Times New Roman">RESTful</font><font face="SimSun">？</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">从<font face="Times New Roman">REST</font><font face="SimSun">的概念上来看，所有可以被抽象为资源的东东都可以使用</font><font face="Times New Roman">RESTful</font><font face="SimSun">的</font><font face="Times New Roman">url</font><font face="SimSun">。因此对于上面的两个问题，如果</font><font face="Times New Roman">login</font><font face="SimSun">和</font><font face="Times New Roman">search</font><font face="SimSun">可以被抽象为资源，那么就可以使用</font><font face="Times New Roman">RESTful</font><font face="SimSun">的</font><font face="Times New Roman">url</font><font face="SimSun">。</font><font face="Times New Roman">search</font><font face="SimSun">比较简单，因为它会返回搜索结果，因此可以被抽象为资源，并且只实现</font><font face="Times New Roman">index</font><font face="SimSun">方法就可以了（只需要显示搜索结果，没有</font><font face="Times New Roman">create</font><font face="SimSun">、</font><font face="Times New Roman">destory</font><font face="SimSun">之类的东西）。然而这里面也有一个问题：</font><font face="Times New Roman">search</font><font face="SimSun">的关键字如何传给</font><font face="Times New Roman">server</font><font face="SimSun">？</font><font face="Times New Roman">index</font><font face="SimSun">方法显然应该使用</font><font face="Times New Roman">HTTP&nbsp;GET</font><font face="SimSun">，这会把关键字加到</font><font face="Times New Roman">url</font><font face="SimSun">后面，当然不符合</font><font face="Times New Roman">REST</font><font face="SimSun">的风格。要解决这个问题，可以把每次</font><font face="Times New Roman">search</font><font face="SimSun">看作一个资源，因此要创建</font><font face="Times New Roman">create</font><font face="SimSun">和</font><font face="Times New Roman">index</font><font face="SimSun">方法，</font><font face="Times New Roman">create</font><font face="SimSun">用来在用户点击</font><font face="Times New Roman">&#8220;</font><font face="SimSun">搜索</font><font face="Times New Roman">&#8221;</font><font face="SimSun">按钮是通过</font><font face="Times New Roman">HTTP&nbsp;POST</font><font face="SimSun">把关键字传给</font><font face="Times New Roman">server</font><font face="SimSun">，然后</font><font face="Times New Roman">index</font><font face="SimSun">则用来显示搜索结果。这样一来，我们还可以记录用户的搜索历史。使用同样的方法，我们也可以对</font><font face="Times New Roman">login</font><font face="SimSun">应用</font><font face="Times New Roman">REST</font><font face="SimSun">，即每次</font><font face="Times New Roman">login</font><font face="SimSun">动作是一个资源。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">现在，我们来复杂一些的东东。如何用<font face="Times New Roman">url</font><font face="SimSun">表达</font><font face="Times New Roman">&#8220;category</font><font face="SimSun">为</font><font face="Times New Roman">ruby</font><font face="SimSun">的</font><font face="Times New Roman">article&#8221;</font><font face="SimSun">？一开始可能想到的是</font><font face="Times New Roman">/category/ruby/articles</font><font face="SimSun">，这种想法很直观。但是我觉得里面的</font><font face="Times New Roman">category</font><font face="SimSun">是不需要的，我们可以直接把</font><font face="Times New Roman">&#8220;/ruby&#8221;</font><font face="SimSun">理解为</font><font face="Times New Roman">&#8220;category</font><font face="SimSun">是</font><font face="Times New Roman">ruby&#8221;</font><font face="SimSun">，也就是说</font><font face="Times New Roman">&#8220;ruby&#8221;</font><font face="SimSun">出现的位置说明了它指的就是</font><font face="Times New Roman">category</font><font face="SimSun">。</font><font face="Times New Roman">OK</font><font face="SimSun">，</font><font face="Times New Roman">/ruby/articles</font><font face="SimSun">，单单从这个</font><font face="Times New Roman">url</font><font face="SimSun">上看，我们能获得多少关于</font><font face="Times New Roman">category</font><font face="SimSun">的信息呢？显然</font><font face="Times New Roman">category</font><font face="SimSun">隐藏在了</font><font face="Times New Roman">url</font><font face="SimSun">后面，这样做到底好不好，应该是仁者见仁，智者见智了。对于如何表达</font><font face="Times New Roman">category</font><font face="SimSun">这样的东西，我还没想出很好的方式，大家有什么好</font><font face="Times New Roman">idea</font><font face="SimSun">，可以一起讨论。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">另外还有一种<font face="Times New Roman">url</font><font face="SimSun">形式，它对应到程序中的继承关系。比如</font><font face="Times New Roman">product</font><font face="SimSun">是一个父类，</font><font face="Times New Roman">book</font><font face="SimSun">和</font><font face="Times New Roman">computer</font><font face="SimSun">是其子类。那么所有产品的</font><font face="Times New Roman">url</font><font face="SimSun">应该是</font><font face="Times New Roman">/products</font><font face="SimSun">，所有书籍的</font><font face="Times New Roman">url</font><font face="SimSun">应该是</font><font face="Times New Roman">/books</font><font face="SimSun">，所有电脑的</font><font face="Times New Roman">url</font><font face="SimSun">应该是</font><font face="Times New Roman">/computers</font><font face="SimSun">。这一想法就比较直观了，而且再次验证了</font><font face="Times New Roman">url</font><font face="SimSun">可以帮助我们进行设计的论点。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">让我再说明一下我的想法：如果每个用户需求都可以抽象为资源，那么就可以完全使用<font face="Times New Roman">REST</font><font face="SimSun">。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">由此看来，使用<font face="Times New Roman">REST</font><font face="SimSun">的关键是如何抽象资源，抽象得越精确，对</font><font face="Times New Roman">REST</font><font face="SimSun">的应用就越好。因此，如何改变我们目前根深蒂固的基于</font><font face="Times New Roman">action</font><font face="SimSun">的思想是最重要的。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">有了对第一个问题的讨论，第二个问题就容易讨论多了。<font face="Times New Roman">REST</font><font face="SimSun">会取代</font><font face="Times New Roman">MVC</font><font face="SimSun">吗？还是彼此是互补关系（就像</font><font face="Times New Roman">AOP</font><font face="SimSun">对于</font><font face="Times New Roman">OOP</font><font face="SimSun">）？答案是</font><font face="Times New Roman">It&nbsp;depends</font><font face="SimSun">！如果我们可以把所有的用户需求都可以抽象为资源，那么</font><font face="Times New Roman">MVC</font><font face="SimSun">就可以推出历史的舞台了。如果情况相反，那么我们就需要混合使用</font><font face="Times New Roman">REST</font><font face="SimSun">和</font><font face="Times New Roman">MVC</font><font face="SimSun">。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">当然，这是非常理想的论断。可能我们无法找到一种方法可以把所有的用户需求都抽象为资源，因为保证这种抽象的完整性（即真的是所有需求都可以）需要形式化的证明。而且即使被证明出来了，由于开发人员的能力和喜好不同，<font face="Times New Roman">MVC</font><font face="SimSun">肯定也会成为不少人的首选。但是对于希望拥抱</font><font face="Times New Roman">REST</font><font face="SimSun">的人来说，这些都没有关系。只要你开发的系统所设计的问题域可以被合理地抽象为资源，那么</font><font face="Times New Roman">REST</font><font face="SimSun">就会成为你的开发利器。</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">所以，所有希望拥抱<font face="Times New Roman">REST</font><font face="SimSun">的朋友们，赶快训练自己如何带上资源的眼镜看世界吧，这才是</font><font face="Times New Roman">REST</font><font face="SimSun">的核心所在。&nbsp;</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">转载自<font face="Times New Roman">javaeye</font><font face="SimSun">论坛　作者：</font><font face="Times New Roman">AllenYoung</font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
<p class="p0" style="margin-top: 0pt; margin-bottom: 0pt; text-indent: 21pt"><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'">原文地址：<font face="Times New Roman">http://www.javaeye.com/topic/70113<br />
<br />
<br />
资源： <a href="http://www.ibm.com/developerworks/cn/web/wa-ajaxarch/">http://www.ibm.com/developerworks/cn/web/wa-ajaxarch/</a></font></span><span style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes'"><o:p></o:p></span></p>
</div>
<!--endfragment-->
<img src ="http://www.blogjava.net/lihao336/aggbug/295494.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2009-09-17 20:06 <a href="http://www.blogjava.net/lihao336/archive/2009/09/17/295494.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]线程上下文类加载器</title><link>http://www.blogjava.net/lihao336/archive/2009/09/17/295489.html</link><dc:creator>calvin</dc:creator><author>calvin</author><pubDate>Thu, 17 Sep 2009 11:15:00 GMT</pubDate><guid>http://www.blogjava.net/lihao336/archive/2009/09/17/295489.html</guid><wfw:comment>http://www.blogjava.net/lihao336/comments/295489.html</wfw:comment><comments>http://www.blogjava.net/lihao336/archive/2009/09/17/295489.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lihao336/comments/commentRss/295489.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lihao336/services/trackbacks/295489.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 线程上下文类加载器问题：何时使用Thread.getContextClassLoader()?这是一个很常见的问题，但答案却很难回答。这个问题通常在需要动态加载类和资源的系统编程时会遇到。总的说来动态加载资源时，往往需要从三种类加载器里选择：系统或说程序的类加载器、当前类加载器、以及当前线程的上下文类加载器。在程序中应该使用何种类加载器呢？系统类加载器通常不会使用。此类加载...&nbsp;&nbsp;<a href='http://www.blogjava.net/lihao336/archive/2009/09/17/295489.html'>阅读全文</a><img src ="http://www.blogjava.net/lihao336/aggbug/295489.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lihao336/" target="_blank">calvin</a> 2009-09-17 19:15 <a href="http://www.blogjava.net/lihao336/archive/2009/09/17/295489.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>