﻿<?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-关注技术，关注生活-文章分类-JAVA</title><link>http://www.blogjava.net/errorfun/category/18234.html</link><description>任何事情只要开始去做，永远不会太迟。</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 12:31:29 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 12:31:29 GMT</pubDate><ttl>60</ttl><item><title>[转]将Java应用程序本地编译为EXE的几种方法</title><link>http://www.blogjava.net/errorfun/articles/86567.html</link><dc:creator>errorfun</dc:creator><author>errorfun</author><pubDate>Sat, 09 Dec 2006 10:33:00 GMT</pubDate><guid>http://www.blogjava.net/errorfun/articles/86567.html</guid><wfw:comment>http://www.blogjava.net/errorfun/comments/86567.html</wfw:comment><comments>http://www.blogjava.net/errorfun/articles/86567.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/errorfun/comments/commentRss/86567.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/errorfun/services/trackbacks/86567.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">将Java应用程序本地编译为EXE的几种方法(推荐使用JOVE和JET)　 <br />1. 从www.towerj.com获得一个TowerJ编译器，该编译器可以将你的CLASS文件　 <br />编译成EXE文件。　<br /> <br />2. 利用微软的SDK-Java 4.0所提供的jexegen.exe创建EXE文件，这个软件可以　 <br />从微软的网站免费下载，地址如下：　 <br /></font>
				<a href="http://www.microsoft.com/java/download/dl_sdk40.htm">
						<font size="2">http://www.microsoft.com/java/download/dl_sdk40.htm</font>
				</a>
				<font size="2">　 <br /></font>
				<font size="2">
						<strong>
								<font color="#666666">jexegen的语法如下：　 <br />jexegen /OUT:exe_file_name　 <br />/MAIN:main_class_name main_class_file_name.class　 <br />[and other classes]　</font> <br /><br /></strong>3. Visual Cafe提供了一个能够创建EXE文件的本地编译器。你需要安装该光盘　 <br />上提供的EXE组件。　<br /> <br />4. 使用InstallAnywhere创建安装盘。　<br /> <br />5. 使用IBM AlphaWorks提供的一个高性能Java编译器，该编译器可以从下面的　 <br />地址获得：　 <br /></font>
				<a href="http://www.alphaworks.ibm.com/tech/hpc">
						<font size="2">http://www.alphaworks.ibm.com/tech/hpc</font>
				</a>
				<font size="2">　 <br /><br />6. JET是一个优秀的Java语言本地编译器。该编译器可以从这个网站获得一个　 <br />测试版本：　 <br /></font>
				<a href="http://www.excelsior-usa.com/jet.html">
						<font size="2">http://www.excelsior-usa.com/jet.html</font>
				</a>
				<font size="2">　 <br /><br />7. Instantiations公司的JOVE　 <br /></font>
				<a href="http://www.instantiations.com/jove/...ejovesystem.htm">
						<font size="2">http://www.instantiations.com/jove/...ejovesystem.htm</font>
				</a>
				<font size="2">　 <br />JOVE公司合并了以前的SuperCede，一个优秀的本地编译器，现在SuperCede　 <br />已经不复存在了。　 <br /><br />8. JToEXE　 <br />Bravo Zulu Consulting, Inc开发的一款本地编译器，本来可以从该公司的　 <br />网页上免费下载的，不过目前在该公司的主页上找不到了。 </font>
		</p>
<img src ="http://www.blogjava.net/errorfun/aggbug/86567.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/errorfun/" target="_blank">errorfun</a> 2006-12-09 18:33 <a href="http://www.blogjava.net/errorfun/articles/86567.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]提高java代码的性能</title><link>http://www.blogjava.net/errorfun/articles/86566.html</link><dc:creator>errorfun</dc:creator><author>errorfun</author><pubDate>Sat, 09 Dec 2006 10:31:00 GMT</pubDate><guid>http://www.blogjava.net/errorfun/articles/86566.html</guid><wfw:comment>http://www.blogjava.net/errorfun/comments/86566.html</wfw:comment><comments>http://www.blogjava.net/errorfun/articles/86566.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/errorfun/comments/commentRss/86566.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/errorfun/services/trackbacks/86566.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">
						<strong>
								<font color="#0033cc">尾递归及其转换 <br /></font>
						</strong>相当多的程序包含有循环，这些循环运行的时间占了程序总运行时间的很大一部分。这些循环经常要反复更新不止一个变量，而每个变量的更新又经常依赖于其它变量的值。 <br /><br />如果把迭代看成是尾递归函数，那么，就可以把这些变量看成是函数的参数。简单提醒一下：如果一个调用的返回值被作为调用函数的值立即返回，那么，这个递归调用就是尾递归；尾递归不必记住调用时调用函数的上下文。 <br /><br />由于这一特点，在尾递归函数和循环之间有一个很好的对应关系：可以简单地把每个递归调用看作是一个循环的多次迭代。但因为所有可变的参数值都一次传给了递归调用，所以比起循环来，在尾递归中可以更容易地得到更新值。而且，难以使用的 break 语句也常常为函数的简单返回所替代。  <br /><br />但在 Java 编程中，用这种方式表示迭代将导致效率低下，因为大量的递归调用有导致堆栈溢出的危险。  <br /><br />解决方案比较简单：因为尾递归函数实际上只是编写循环的一种更简单的方式，所以就让编译器把它们自动转换成循环形式。这样您就同时利用了这两种形式的优点。  <br /><br />但是，尽管大家都熟知如何把一个尾递归函数自动转换成一个简单循环，Java 规范却不要求做这种转换。不作这种要求的原因大概是：通常在面向对象的语言中，这种转换不能静态地进行。相反地，这种从尾递归函数到简单循环的转换必须由 JIT 编译器动态地进行。  <br /><br />要理解为什么会是这样，考虑下面一个失败的尝试：在 Integers 集上，把 Iterator 中的元素相乘。  <br /><br />因为下面的程序中有一个错误，所以在运行时会抛出一个异常。但是，就象在本专栏以前的许多文章中已经论证的那样，一个程序抛出的精确异常（跟很棒的错误类型标识符一样）对于找到错误藏在程序的什么地方并没有什么帮助，我们也不想编译器以这种方式改变程序，以使编译的结果代码抛出一个不同的异常。  <br /><br /></font>
				<strong>
						<font size="2">[清单 1. 一个把 Integer 集的 Iterator 中的元素相乘的失败尝试 ]<br /></font>
				</strong>
				<strong>
						<br />
				</strong>
				<font size="2">
				</font>
		</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">import</span>
				<span style="COLOR: #000000"> java.util.Iterator; <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><br /><img id="Codehighlighter1_50_335_Open_Image" onclick="this.style.display='none'; Codehighlighter1_50_335_Open_Text.style.display='none'; Codehighlighter1_50_335_Closed_Image.style.display='inline'; Codehighlighter1_50_335_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_50_335_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_50_335_Closed_Text.style.display='none'; Codehighlighter1_50_335_Open_Image.style.display='inline'; Codehighlighter1_50_335_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Example </span>
				<span id="Codehighlighter1_50_335_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_50_335_Open_Text">
						<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_87_123_Open_Image" onclick="this.style.display='none'; Codehighlighter1_87_123_Open_Text.style.display='none'; Codehighlighter1_87_123_Closed_Image.style.display='inline'; Codehighlighter1_87_123_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_87_123_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_87_123_Closed_Text.style.display='none'; Codehighlighter1_87_123_Open_Image.style.display='inline'; Codehighlighter1_87_123_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> product(Iterator i) </span>
						<span id="Codehighlighter1_87_123_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_87_123_Open_Text">
								<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">return</span>
								<span style="COLOR: #000000"> productHelp(i, </span>
								<span style="COLOR: #000000">0</span>
								<span style="COLOR: #000000">); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_174_332_Open_Image" onclick="this.style.display='none'; Codehighlighter1_174_332_Open_Text.style.display='none'; Codehighlighter1_174_332_Closed_Image.style.display='inline'; Codehighlighter1_174_332_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_174_332_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_174_332_Closed_Text.style.display='none'; Codehighlighter1_174_332_Open_Image.style.display='inline'; Codehighlighter1_174_332_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> productHelp(Iterator i, </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> accumulator) </span>
						<span id="Codehighlighter1_174_332_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_174_332_Open_Text">
								<span style="COLOR: #000000">{ <br /><img id="Codehighlighter1_198_281_Open_Image" onclick="this.style.display='none'; Codehighlighter1_198_281_Open_Text.style.display='none'; Codehighlighter1_198_281_Closed_Image.style.display='inline'; Codehighlighter1_198_281_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_198_281_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_198_281_Closed_Text.style.display='none'; Codehighlighter1_198_281_Open_Image.style.display='inline'; Codehighlighter1_198_281_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">if</span>
								<span style="COLOR: #000000"> (i.hasNext()) </span>
								<span id="Codehighlighter1_198_281_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.blogjava.net/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_198_281_Open_Text">
										<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />      </span>
										<span style="COLOR: #0000ff">return</span>
										<span style="COLOR: #000000"> productHelp(i, accumulator </span>
										<span style="COLOR: #000000">*</span>
										<span style="COLOR: #000000"> ((Integer)i.next()).intValue()); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
								</span>
								<span style="COLOR: #000000"> <br /><img id="Codehighlighter1_293_327_Open_Image" onclick="this.style.display='none'; Codehighlighter1_293_327_Open_Text.style.display='none'; Codehighlighter1_293_327_Closed_Image.style.display='inline'; Codehighlighter1_293_327_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_293_327_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_293_327_Closed_Text.style.display='none'; Codehighlighter1_293_327_Open_Image.style.display='inline'; Codehighlighter1_293_327_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">else</span>
								<span style="COLOR: #000000"> </span>
								<span id="Codehighlighter1_293_327_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.blogjava.net/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_293_327_Open_Text">
										<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />      </span>
										<span style="COLOR: #0000ff">return</span>
										<span style="COLOR: #000000"> accumulator; <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
								</span>
								<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000"> </span>
		</div>
		<p>
				<br />注意 product 方法中的错误。product 方法通过把 accumulator 赋值为 0 调用 productHelp。它的值应为 1。否则，在类 Example 的任何实例上调用 product 都将产生 0 值，不管 Iterator 是什么值。  <br /><br />假设这个错误终于被改正了，但同时，类 Example 的一个子类也被创建了，如清单 2 所示： <br /><br /><strong>[清单 2. 试图捕捉象清单 1 这样的不正确的调用]</strong> <br /><br /><font size="2"><font color="#ff0000"></font></font></p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">import</span>
				<span style="COLOR: #000000"> java.util.</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">; <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><br /><img id="Codehighlighter1_36_321_Open_Image" onclick="this.style.display='none'; Codehighlighter1_36_321_Open_Text.style.display='none'; Codehighlighter1_36_321_Closed_Image.style.display='inline'; Codehighlighter1_36_321_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_36_321_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_36_321_Closed_Text.style.display='none'; Codehighlighter1_36_321_Open_Image.style.display='inline'; Codehighlighter1_36_321_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Example </span>
				<span id="Codehighlighter1_36_321_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_36_321_Open_Text">
						<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_73_109_Open_Image" onclick="this.style.display='none'; Codehighlighter1_73_109_Open_Text.style.display='none'; Codehighlighter1_73_109_Closed_Image.style.display='inline'; Codehighlighter1_73_109_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_73_109_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_73_109_Closed_Text.style.display='none'; Codehighlighter1_73_109_Open_Image.style.display='inline'; Codehighlighter1_73_109_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> product(Iterator i) </span>
						<span id="Codehighlighter1_73_109_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_73_109_Open_Text">
								<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">return</span>
								<span style="COLOR: #000000"> productHelp(i, </span>
								<span style="COLOR: #000000">1</span>
								<span style="COLOR: #000000">); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_160_318_Open_Image" onclick="this.style.display='none'; Codehighlighter1_160_318_Open_Text.style.display='none'; Codehighlighter1_160_318_Closed_Image.style.display='inline'; Codehighlighter1_160_318_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_160_318_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_160_318_Closed_Text.style.display='none'; Codehighlighter1_160_318_Open_Image.style.display='inline'; Codehighlighter1_160_318_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> productHelp(Iterator i, </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> accumulator) </span>
						<span id="Codehighlighter1_160_318_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_160_318_Open_Text">
								<span style="COLOR: #000000">{ <br /><img id="Codehighlighter1_184_267_Open_Image" onclick="this.style.display='none'; Codehighlighter1_184_267_Open_Text.style.display='none'; Codehighlighter1_184_267_Closed_Image.style.display='inline'; Codehighlighter1_184_267_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_184_267_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_184_267_Closed_Text.style.display='none'; Codehighlighter1_184_267_Open_Image.style.display='inline'; Codehighlighter1_184_267_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">if</span>
								<span style="COLOR: #000000"> (i.hasNext()) </span>
								<span id="Codehighlighter1_184_267_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.blogjava.net/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_184_267_Open_Text">
										<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />      </span>
										<span style="COLOR: #0000ff">return</span>
										<span style="COLOR: #000000"> productHelp(i, accumulator </span>
										<span style="COLOR: #000000">*</span>
										<span style="COLOR: #000000"> ((Integer)i.next()).intValue()); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
								</span>
								<span style="COLOR: #000000"> <br /><img id="Codehighlighter1_279_313_Open_Image" onclick="this.style.display='none'; Codehighlighter1_279_313_Open_Text.style.display='none'; Codehighlighter1_279_313_Closed_Image.style.display='inline'; Codehighlighter1_279_313_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_279_313_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_279_313_Closed_Text.style.display='none'; Codehighlighter1_279_313_Open_Image.style.display='inline'; Codehighlighter1_279_313_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">else</span>
								<span style="COLOR: #000000"> </span>
								<span id="Codehighlighter1_279_313_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.blogjava.net/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_279_313_Open_Text">
										<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />      </span>
										<span style="COLOR: #0000ff">return</span>
										<span style="COLOR: #000000"> accumulator; <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
								</span>
								<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000"> </span>
		</div>
		<p> </p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000"> And, in a separate file: </span>
				<span style="COLOR: #008000">
						<br />
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">import</span>
				<span style="COLOR: #000000"> java.util.</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">; <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><br /><img id="Codehighlighter1_91_493_Open_Image" onclick="this.style.display='none'; Codehighlighter1_91_493_Open_Text.style.display='none'; Codehighlighter1_91_493_Closed_Image.style.display='inline'; Codehighlighter1_91_493_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_91_493_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_91_493_Closed_Text.style.display='none'; Codehighlighter1_91_493_Open_Image.style.display='inline'; Codehighlighter1_91_493_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> Example2 </span>
				<span style="COLOR: #0000ff">extends</span>
				<span style="COLOR: #000000"> Example </span>
				<span id="Codehighlighter1_91_493_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_91_493_Open_Text">
						<span style="COLOR: #000000">{ <br /><img id="Codehighlighter1_141_327_Open_Image" onclick="this.style.display='none'; Codehighlighter1_141_327_Open_Text.style.display='none'; Codehighlighter1_141_327_Closed_Image.style.display='inline'; Codehighlighter1_141_327_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_141_327_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_141_327_Closed_Text.style.display='none'; Codehighlighter1_141_327_Open_Image.style.display='inline'; Codehighlighter1_141_327_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> productHelp(Iterator i, </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> accumulator) </span>
						<span id="Codehighlighter1_141_327_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_141_327_Open_Text">
								<span style="COLOR: #000000">{ <br /><img id="Codehighlighter1_169_254_Open_Image" onclick="this.style.display='none'; Codehighlighter1_169_254_Open_Text.style.display='none'; Codehighlighter1_169_254_Closed_Image.style.display='inline'; Codehighlighter1_169_254_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_169_254_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_169_254_Closed_Text.style.display='none'; Codehighlighter1_169_254_Open_Image.style.display='inline'; Codehighlighter1_169_254_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">if</span>
								<span style="COLOR: #000000"> (accumulator </span>
								<span style="COLOR: #000000">&lt;</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">1</span>
								<span style="COLOR: #000000">) </span>
								<span id="Codehighlighter1_169_254_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.blogjava.net/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_169_254_Open_Text">
										<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />      </span>
										<span style="COLOR: #0000ff">throw</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #0000ff">new</span>
										<span style="COLOR: #000000"> RuntimeException(</span>
										<span style="COLOR: #000000">"</span>
										<span style="COLOR: #000000">accumulator to productHelp must be &gt;= 1</span>
										<span style="COLOR: #000000">"</span>
										<span style="COLOR: #000000">); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
								</span>
								<span style="COLOR: #000000"> <br /><img id="Codehighlighter1_266_322_Open_Image" onclick="this.style.display='none'; Codehighlighter1_266_322_Open_Text.style.display='none'; Codehighlighter1_266_322_Closed_Image.style.display='inline'; Codehighlighter1_266_322_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_266_322_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_266_322_Closed_Text.style.display='none'; Codehighlighter1_266_322_Open_Image.style.display='inline'; Codehighlighter1_266_322_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">else</span>
								<span style="COLOR: #000000"> </span>
								<span id="Codehighlighter1_266_322_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.blogjava.net/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_266_322_Open_Text">
										<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />      </span>
										<span style="COLOR: #0000ff">return</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #0000ff">super</span>
										<span style="COLOR: #000000">.productHelp(i, accumulator); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
								</span>
								<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_372_490_Open_Image" onclick="this.style.display='none'; Codehighlighter1_372_490_Open_Text.style.display='none'; Codehighlighter1_372_490_Closed_Image.style.display='inline'; Codehighlighter1_372_490_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_372_490_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_372_490_Closed_Text.style.display='none'; Codehighlighter1_372_490_Open_Image.style.display='inline'; Codehighlighter1_372_490_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </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">void</span>
						<span style="COLOR: #000000"> main(String[] args) </span>
						<span id="Codehighlighter1_372_490_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_372_490_Open_Text">
								<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    LinkedList l </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">new</span>
								<span style="COLOR: #000000"> LinkedList(); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    l.add(</span>
								<span style="COLOR: #0000ff">new</span>
								<span style="COLOR: #000000"> Integer(</span>
								<span style="COLOR: #000000">0</span>
								<span style="COLOR: #000000">)); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">new</span>
								<span style="COLOR: #000000"> Example2().product(l.listIterator()); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>类 Example2 中的被覆盖的 productHelp 方法试图通过当 accumulator 小于“1”时抛出运行时异常来捕捉对 productHelp 的不正确调用。不幸的是，这样做将引入一个新的错误。如果 Iterator 含有任何 0 值的实例，都将使 productHelp 在自身的递归调用上崩溃。  <br /><br />现在请注意，在类 Example2 的 main 方法中，创建了 Example2 的一个实例并调用了它的 product 方法。由于传给这个方法的 Iterator 包含一个 0，因此程序将崩溃。  <br /><br />然而，您可以看到类 Example 的 productHelp 是严格尾递归的。假设一个静态编译器想把这个方法的正文转换成一个循环，如清单 3 所示：  <br /><br /><strong>[清单 3. 静态编译不会优化尾调用的一个示例]</strong>  <br /><br /><font size="2"><font color="#ff0000"></font></font></p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img id="Codehighlighter1_45_163_Open_Image" onclick="this.style.display='none'; Codehighlighter1_45_163_Open_Text.style.display='none'; Codehighlighter1_45_163_Closed_Image.style.display='inline'; Codehighlighter1_45_163_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_45_163_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_45_163_Closed_Text.style.display='none'; Codehighlighter1_45_163_Open_Image.style.display='inline'; Codehighlighter1_45_163_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> productHelp(Iterator i, </span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> accumulator) </span>
				<span id="Codehighlighter1_45_163_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_45_163_Open_Text">
						<span style="COLOR: #000000">{ <br /><img id="Codehighlighter1_72_133_Open_Image" onclick="this.style.display='none'; Codehighlighter1_72_133_Open_Text.style.display='none'; Codehighlighter1_72_133_Closed_Image.style.display='inline'; Codehighlighter1_72_133_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_72_133_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_72_133_Closed_Text.style.display='none'; Codehighlighter1_72_133_Open_Image.style.display='inline'; Codehighlighter1_72_133_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">while</span>
						<span style="COLOR: #000000"> (i.hasNext()) </span>
						<span id="Codehighlighter1_72_133_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_72_133_Open_Text">
								<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />      accumulator </span>
								<span style="COLOR: #000000">*=</span>
								<span style="COLOR: #000000"> ((Integer)i.next()).intValue(); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000"> accumulator; <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />  }</span>
				</span>
				<span style="COLOR: #000000"> </span>
		</div>
		<p>
				<br />
				<br />于是，最初对 productHelp 的调用，结果成了对超类的方法的调用。超方法将通过简单地在 iterator 上循环来计算其结果。不会抛出任何异常。  <br /><br />用两个不同的静态编译器来编译这段代码，结果是一个会抛出异常，而另一个则不会，想想这是多么让人感到困惑。  <br /><br /><font size="2"><font color="#0033cc"><strong>您的 JIT 会做这种转换吗？<br /></strong></font>因此，如清单 3 中的示例所示，我们不能期望静态编译器会在保持语言语义的同时对 Java 代码执行尾递归转换。相反地，我们必须依靠 JIT 进行的动态编译。JIT 会不会做这种转换是取决于 JVM。  <br /><br />要判断您的 JIT 会否转换尾递归的一个办法是编译并运行如下小测试类：  <br /><br /><strong>[清单 4. 判断您的 JIT 能否转换尾递归]</strong><br /><br /></font><font size="2"><font color="#ff0000"></font></font></p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img id="Codehighlighter1_31_161_Open_Image" onclick="this.style.display='none'; Codehighlighter1_31_161_Open_Text.style.display='none'; Codehighlighter1_31_161_Closed_Image.style.display='inline'; Codehighlighter1_31_161_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_31_161_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_31_161_Closed_Text.style.display='none'; Codehighlighter1_31_161_Open_Image.style.display='inline'; Codehighlighter1_31_161_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> TailRecursionTest </span>
				<span id="Codehighlighter1_31_161_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_31_161_Open_Text">
						<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_68_94_Open_Image" onclick="this.style.display='none'; Codehighlighter1_68_94_Open_Text.style.display='none'; Codehighlighter1_68_94_Closed_Image.style.display='inline'; Codehighlighter1_68_94_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_68_94_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_68_94_Closed_Text.style.display='none'; Codehighlighter1_68_94_Open_Image.style.display='inline'; Codehighlighter1_68_94_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">private</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">static</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> loop(</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> i) </span>
						<span id="Codehighlighter1_68_94_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_68_94_Open_Text">
								<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">return</span>
								<span style="COLOR: #000000"> loop(i); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_139_158_Open_Image" onclick="this.style.display='none'; Codehighlighter1_139_158_Open_Text.style.display='none'; Codehighlighter1_139_158_Closed_Image.style.display='inline'; Codehighlighter1_139_158_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_139_158_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_139_158_Closed_Text.style.display='none'; Codehighlighter1_139_158_Open_Image.style.display='inline'; Codehighlighter1_139_158_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </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">void</span>
						<span style="COLOR: #000000"> main(String[] args) </span>
						<span id="Codehighlighter1_139_158_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_139_158_Open_Text">
								<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    loop(</span>
								<span style="COLOR: #000000">0</span>
								<span style="COLOR: #000000">); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000"> </span>
		</div>
		<p>
				<br />
				<br />我们来考虑一下这个类的 loop 方法。这个方法只是尽可能长时间地对自身作递归调用。因为它永远不会返回，也不会以任何方式影响任何外部变量，因此如清单 5 所示替换其代码正文将保留程序的语义。  <br /><br /><strong>[清单 5. 一个动态转换]</strong><br /><br /><font size="2"><font color="#ff0000"></font></font></p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img id="Codehighlighter1_31_167_Open_Image" onclick="this.style.display='none'; Codehighlighter1_31_167_Open_Text.style.display='none'; Codehighlighter1_31_167_Closed_Image.style.display='inline'; Codehighlighter1_31_167_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_31_167_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_31_167_Closed_Text.style.display='none'; Codehighlighter1_31_167_Open_Image.style.display='inline'; Codehighlighter1_31_167_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> TailRecursionTest </span>
				<span id="Codehighlighter1_31_167_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_31_167_Open_Text">
						<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_68_100_Open_Image" onclick="this.style.display='none'; Codehighlighter1_68_100_Open_Text.style.display='none'; Codehighlighter1_68_100_Closed_Image.style.display='inline'; Codehighlighter1_68_100_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_68_100_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_68_100_Closed_Text.style.display='none'; Codehighlighter1_68_100_Open_Image.style.display='inline'; Codehighlighter1_68_100_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </span>
						<span style="COLOR: #0000ff">private</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">static</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> loop(</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> i) </span>
						<span id="Codehighlighter1_68_100_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_68_100_Open_Text">
								<span style="COLOR: #000000">{ <br /><img id="Codehighlighter1_88_95_Open_Image" onclick="this.style.display='none'; Codehighlighter1_88_95_Open_Text.style.display='none'; Codehighlighter1_88_95_Closed_Image.style.display='inline'; Codehighlighter1_88_95_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_88_95_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_88_95_Closed_Text.style.display='none'; Codehighlighter1_88_95_Open_Image.style.display='inline'; Codehighlighter1_88_95_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
								<span style="COLOR: #0000ff">while</span>
								<span style="COLOR: #000000"> (</span>
								<span style="COLOR: #0000ff">true</span>
								<span style="COLOR: #000000">) </span>
								<span id="Codehighlighter1_88_95_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.blogjava.net/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_88_95_Open_Text">
										<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
								</span>
								<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_145_164_Open_Image" onclick="this.style.display='none'; Codehighlighter1_145_164_Open_Text.style.display='none'; Codehighlighter1_145_164_Closed_Image.style.display='inline'; Codehighlighter1_145_164_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_145_164_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_145_164_Closed_Text.style.display='none'; Codehighlighter1_145_164_Open_Image.style.display='inline'; Codehighlighter1_145_164_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />  </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">void</span>
						<span style="COLOR: #000000"> main(String[] args) </span>
						<span id="Codehighlighter1_145_164_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_145_164_Open_Text">
								<span style="COLOR: #000000">{ <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    loop(</span>
								<span style="COLOR: #000000">0</span>
								<span style="COLOR: #000000">); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />  }</span>
						</span>
						<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000"> </span>
		</div>
		<p>
				<br />  <br />而且，事实上这也就是足够完善的编译器所做的转换。  <br /><br />如果您的 JIT 编译器把尾递归调用转换成迭代，这个程序将无限期地运行下去。它所需的内存很小，而且不会随时间增加。  <br /><br />另一方面，如果 JIT 不做这种转换，程序将会很快耗尽堆栈空间并报告一个堆栈溢出错误。  <br /><br />我在两个 Java SDK 上运行这个程序，结果令人惊讶。在 SUN 公司的 Hotspot JVM（版本 1.3 ）上运行时，发现 Hotspot 不执行这种转换。缺省设置下，在我的机器上运行时，不到一秒钟堆栈空间就被耗尽了。  <br /><br />另一方面，程序在 IBM 的 JVM（版本 1.3 ）上咕噜噜运行时却没有任何问题，这表明 IBM 的 JVM 以这种方式转换代码。  <br /><br /><font size="2"><strong><font color="#0033cc">总结<br /></font></strong>记住：我们不能寄希望于我们的代码会总是运行在会转换尾递归调用的 JVM 上。因此，为了保证您的程序在所有 JVM 上都有适当的性能，您应始终努力把那些最自然地符合尾递归模式的代码按迭代风格编写。  <br /><br />但是请注意：就象我们的示例所演示的那样，以这种方式转换代码时很容易引入错误，不论是由人工还是由软件来完成这种转换。</font></p>
		<p align="right">
				<font size="2">文章摘自：</font>
				<a href="http://www-900.ibm.com/">
						<font size="2">http://www-900.ibm.com/</font>
				</a>
				<br />
				<font size="2">作者：Eric Allen</font>
		</p>
<img src ="http://www.blogjava.net/errorfun/aggbug/86566.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/errorfun/" target="_blank">errorfun</a> 2006-12-09 18:31 <a href="http://www.blogjava.net/errorfun/articles/86566.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Java线程的缺陷</title><link>http://www.blogjava.net/errorfun/articles/86532.html</link><dc:creator>errorfun</dc:creator><author>errorfun</author><pubDate>Sat, 09 Dec 2006 05:50:00 GMT</pubDate><guid>http://www.blogjava.net/errorfun/articles/86532.html</guid><wfw:comment>http://www.blogjava.net/errorfun/comments/86532.html</wfw:comment><comments>http://www.blogjava.net/errorfun/articles/86532.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/errorfun/comments/commentRss/86532.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/errorfun/services/trackbacks/86532.html</trackback:ping><description><![CDATA[
		<font size="2">Java 语言的线程模型是此语言的一个最难另人满意的部分。尽管 Java 语言本身就支持线程编程是件好事，但是它对线程的语法和类包的支持太少，只能适用于极小型的应用环境。<br /><br />关于 Java 线程编程的大多数书籍都长篇累牍地指出了 Java 线程模型的缺陷，并提供了解决这些问题的急救包(Band-Aid/邦迪创可贴)类库。我称这些类为急救包，是因为它们所能解决的问题本应是由 Java 语言本身语法所包含的。从长远来看，以语法而不是类库方法，将能产生更高效的代码。这是因为编译器和 Java 虚拟器 (JVM) 能一同优化程序代码，而这些优化对于类库中的代码是很难或无法实现的。<br /><br />在我的《Taming Java Threads 》（请参阅 参考资料 ）书中以及本文中，我进一步建议对 Java 编程语言本身进行一些修改，以使得它能够真正解决这些线程编程的问题。本文和我这本书的主要区别是，我在撰写本文时进行了更多的思考, 所以对书中的提议加以了提高。这些建议只是尝试性的 -- 只是我个人对这些问题的想法，而且实现这些想法需要进行大量的工作以及同行们的评价。但这是毕竟是一个开端，我有意为解决这些问题成立一个专门的工作组，如果您感兴趣，请发 e-mail 到 </font>
		<a href="mailto:threading@holub.com" target="_blank">
				<font size="2">threading@holub.com</font>
		</a>
		<font size="2"> 。一旦我真正着手进行，我就会给您发通知。<br /><br />这里提出的建议是非常大胆的。有些人建议对 Java 语言规范 (JLS)（请参阅参考资料 ）进行细微和少量的修改以解决当前模糊的 JVM 行为，但是我却想对其进行更为彻底的改进。<br /><br />在实际草稿中，我的许多建议包括为此语言引入新的关键字。虽然通常要求不要突破一个语言的现有代码是正确的，但是如果该语言的并不是要保持不变以至于过时的话，它就必须能引入新的关键字。为了使引入的关键字与现有的标识符不产生冲突，经过细心考虑，我将使用一个 ($) 字符，而这个字符在现有的标识符中是非法的。(例如，使用 $task，而不是 task)。此时需要编译器的命令行开关提供支持，能使用这些关键字的变体，而不是忽略这个美元符号。</font>
		<p>
				<font size="2">
						<strong>task（任务）的概念<br /><br /></strong>Java 线程模型的根本问题是它完全不是面向对象的。面向对象 (OO) 设计人员根本不按线程角度考虑问题；他们考虑的是同步 信息 异步 信息（同步信息被立即处理 -- 直到信息处理完成才返回消息句柄；异步信息收到后将在后台处理一段时间 -- 而早在信息处理结束前就返回消息句柄）。Java 编程语言中的 Toolkit.getImage() 方法就是异步信息的一个好例子。 getImage() 的消息句柄将被立即返回，而不必等到整个图像被后台线程取回。<br /><br />这是面向对象 (OO) 的处理方法。但是，如前所述，Java 的线程模型是非面向对象的。一个 Java 编程语言线程实际上只是一个run() 过程，它调用了其它的过程。在这里就根本没有对象、异步或同步信息以及其它概念。<br /><br />对于此问题，在我的书中深入讨论过的一个解决方法是，使用一个Active_object。 active 对象是可以接收异步请求的对象，它在接收到请求后的一段时间内以后台方式得以处理。在 Java 编程语言中，一个请求可被封装在一个对象中。例如，你可以把一个通过 Runnable 接口实现的实例传送给此 active 对象，该接口的 run() 方法封装了需要完成的工作。该 runnable 对象被此 active 对象排入到队列中，当轮到它执行时，active 对象使用一个后台线程来执行它。<br /><br />在一个 active 对象上运行的异步信息实际上是同步的，因为它们被一个单一的服务线程按顺序从队列中取出并执行。因此，使用一个 active 对象以一种更为过程化的模型可以消除大多数的同步问题。<br /><br />在某种意义上，Java 编程语言的整个 Swing/AWT 子系统是一个 active 对象。向一个 Swing 队列传送一条讯息的唯一安全的途径是，调用一个类似SwingUtilities.invokeLater() 的方法，这样就在 Swing 事件队列上发送了一个 runnable 对象，当轮到它执行时， Swing 事件处理线程将会处理它。<br /><br />那么我的第一个建议是，向 Java 编程语言中加入一个task （任务）的概念，从而将active 对象集成到语言中。( task的概念是从 Intel 的 RMX 操作系统和 Ada 编程语言借鉴过来的。大多数实时操作系统都支持类似的概念。）<br /><br />一个任务有一个内置的 active 对象分发程序，并自动管理那些处理异步信息的全部机制。<br /><br />定义一个任务和定义一个类基本相同，不同的只是需要在任务的方法前加一个asynchronous 修饰符来指示 active 对象的分配程序在后台处理这些方法。请参考我的书中第九章的基于类方法，再看以下的 file_io 类，它使用了在《 Taming Java Threads 》中所讨论的 Active_object 类来实现异步写操作：<br /><br />所有的写请求都用一个dispatch() 过程调用被放在 active-object 的输入队列中排队。在后台处理这些异步信息时出现的任何异常 (exception) 都由 Exception_handler 对象处理，此 Exception_handler 对象被传送到 File_io_task 的构造函数中。您要写内容到文件时，代码如下：<br /><br />这种基于类的处理方法，其主要问题是太复杂了 -- 对于一个这样简单的操作，代码太杂了。向 Java 语言引入$task 和 $asynchronous 关键字后，就可以按下面这样重写以前的代码：<br /><br />注意，异步方法并没有指定返回值，因为其句柄将被立即返回，而不用等到请求的操作处理完成后。所以，此时没有合理的返回值。对于派生出的模型，$task 关键字和 class 一样同效： $task 可以实现接口、继承类和继承的其它任务。标有 asynchronous 关键字的方法由 $task 在后台处理。其它的方法将同步运行，就像在类中一样。<br /><br />$task关键字可以用一个可选的 $error 从句修饰 (如上所示)，它表明对任何无法被异步方法本身捕捉的异常将有一个缺省的处理程序。我使用 $ 来代表被抛出的异常对象。如果没有指定 $error 从句，就将打印出一个合理的出错信息（很可能是堆栈跟踪信息）。<br /><br />注意，为确保线程安全，异步方法的参数必须是不变 (immutable) 的。运行时系统应通过相关语义来保证这种不变性（简单的复制通常是不够的）。<br /><br />所有的 task 对象必须支持一些伪信息 (pseudo-message)，例如：<br /><br />除了常用的修饰符（public 等)， task 关键字还应接受一个 $pooled(n) 修饰符，它导致 task 使用一个线程池，而不是使用单个线程来运行异步请求。 n 指定了所需线程池的大小；必要时，此线程池可以增加，但是当不再需要线程时，它应该缩到原来的大小。伪域 (pseudo-field) $pool_size 返回在 $pooled(n) 中指定的原始 n 参数值。<br /><br />在《Taming Java Threads 》的第八章中，我给出了一个服务器端的 socket 处理程序，作为线程池的例子。它是关于使用线程池的任务的一个好例子。其基本思路是产生一个独立对象，它的任务是监控一个服务器端的 socket。每当一个客户机连接到服务器时，服务器端的对象会从池中抓取一个预先创建的睡眠线程，并把此线程设置为服务于客户端连接。socket 服务器会产出一个额外的客户服务线程，但是当连接关闭时，这些额外的线程将被删除。实现 socket 服务器的推荐语法如下：<br /><br />Socket_server对象使用一个独立的后台线程处理异步的 listen() 请求，它封装 socket 的"接受"循环。当每个客户端连接时， listen() 请求一个 Client_handler 通过调用 handle() 来处理请求。每个 handle() 请求在它们自己的线程中执行（因为这是一个 $pooled 任务)。<br /><br />注意，每个传送到$pooled $task 的异步消息实际上都使用它们自己的线程来处理。典型情况下，由于一个 $pooled $task 用于实现一个自主操作；所以对于解决与访问状态变量有关的潜在的同步问题，最好的解决方法是在 $asynchronous 方法中使用 this 是指向的对象的一个独有副本。这就是说，当向一个 $pooled $task 发送一个异步请求时，将执行一个 clone() 操作，并且此方法的 this 指针会指向此克隆对象。线程之间的通信可通过对 static 区的同步访问实现。</font>
		</p>
		<br />
		<p>
				<font size="2">
						<strong>改进synchronized<br /></strong>
						<br />虽然在多数情况下，$task 消除了同步操作的要求，但是不是所有的多线程系统都用任务来实现。所以，还需要改进现有的线程模块。 synchronized 关键字有下列缺点： 无法指定一个超时值。 无法中断一个正在等待请求锁的线程。 无法安全地请求多个锁 。(多个锁只能以依次序获得。)<br /><br />解决这些问题的办法是：扩展synchronized 的语法，使它支持多个参数和能接受一个超时说明（在下面的括弧中指定）。下面是我希望的语法：<br /><br />synchronized(x &amp;&amp; y &amp;&amp; z) 获得 x、y 和 z 对象的锁。 <br />synchronized(x || y || z) 获得 x、y 或 z 对象的锁。 <br />synchronized( (x &amp;&amp; y ) || z) 对于前面代码的一些扩展。 <br />synchronized(...)[1000] 设置 1 秒超时以获得一个锁。 <br />synchronized[1000] f(){...} 在进入 f() 函数时获得 this 的锁，但可有 1 秒超时。 <br /><br />TimeoutException是 RuntimeException 派生类，它在等待超时后即被抛出。<br /><br />超时是需要的，但还不足以使代码强壮。您还需要具备从外部中止请求锁等待的能力。所以，当向一个等待锁的线程传送一个interrupt() 方法后，此方法应抛出一个 SynchronizationException 对象，并中断等待的线程。这个异常应是 RuntimeException 的一个派生类，这样不必特别处理它。<br /><br />对synchronized 语法这些推荐的更改方法的主要问题是，它们需要在二进制代码级上修改。而目前这些代码使用进入监控(enter-monitor)和退出监控(exit-monitor)指令来实现 synchronized 。而这些指令没有参数，所以需要扩展二进制代码的定义以支持多个锁定请求。但是这种修改不会比在 Java 2 中修改 Java 虚拟机的更轻松，但它是向下兼容现存的 Java 代码。<br /><br />另一个可解决的问题是最常见的死锁情况，在这种情况下，两个线程都在等待对方完成某个操作。设想下面的一个例子（假设的）：<br /><br />设想一个线程调用a() ，但在获得　 lock1 之后在获得 lock2 之前被剥夺运行权。 第二个线程进入运行，调用 b() ，获得了 lock2 ，但是由于第一个线程占用 lock1 ，所以它无法获得 lock1 ，所以它随后处于等待状态。此时第一个线程被唤醒，它试图获得 lock2 ，但是由于被第二个线程占据，所以无法获得。此时出现死锁。下面的 synchronize-on-multiple-objects 的语法可解决这个问题：<br /><br />编译器(或虚拟机)会重新排列请求锁的顺序，使lock1 总是被首先获得，这就消除了死锁。<br /><br />但是，这种方法对多线程不一定总成功，所以得提供一些方法来自动打破死锁。一个简单的办法就是在等待第二个锁时常释放已获得的锁。这就是说，应采取如下的等待方式，而不是永远等待：<br /><br />如果等待锁的每个程序使用不同的超时值，就可打破死锁而其中一个线程就可运行。我建议用以下的语法来取代前面的代码：<br /><br />synchronized语句将永远等待，但是它时常会放弃已获得的锁以打破潜在的死锁可能。在理想情况下，每个重复等待的超时值比前一个相差一随机值。<br /><br /><strong>改进wait() 和 notify()</strong><br /><br />wait()/ notify() 系统也有一些问题： 无法检测 wait() 是正常返回还是因超时返回。 无法使用传统条件变量来实现处于一个"信号"(signaled)状态。 太容易发生嵌套的监控(monitor)锁定。<br /><br />超时检测问题可以通过重新定义wait() 使它返回一个 boolean 变量 (而不是 void ) 来解决。一个 true 返回值指示一个正常返回，而 false 指示因超时返回。<br /><br />基于状态的条件变量的概念是很重要的。如果此变量被设置成false 状态，那么等待的线程将要被阻断，直到此变量进入 true 状态；任何等待 true 的条件变量的等待线程会被自动释放。 (在这种情况下， wait() 调用不会发生阻断。)。通过如下扩展 notify() 的语法，可以支持这个功能：<br /><br />嵌套监控锁定问题非常麻烦，我并没有简单的解决办法。嵌套监控锁定是一种死锁形式，当某个锁的占有线程在挂起其自身之前不释放锁时，会发生这种嵌套监控封锁。下面是此问题的一个例子（还是假设的），但是实际的例子是非常多的：<br /><br />此例中，在get() 和 put() 操作中涉及两个锁：一个在 Stack 对象上，另一个在 LinkedList 对象上。下面我们考虑当一个线程试图调用一个空栈的 pop() 操作时的情况。此线程获得这两个锁，然后调用 wait() 释放 Stack 对象上 的锁，但是没有释放在 list 上的锁。如果此时第二个线程试图向堆栈中压入一个对象，它会在 synchronized(list) 语句上永远挂起，而且永远不会被允许压入一个对象。由于第一个线程等待的是一个非空栈，这样就会发生死锁。这就是说，第一个线程永远无法从 wait() 返回，因为由于它占据着锁，而导致第二个线程永远无法运行到 notify() 语句。<br /><br />在这个例子中，有很多明显的办法来解决问题：例如，对任何的方法都使用同步。但是在真实世界中，解决方法通常不是这么简单。<br /><br />一个可行的方法是，在wait() 中按照反顺序释放当前线程获取的 所有 锁，然后当等待条件满足后，重新按原始获取顺序取得它们。但是，我能想象出利用这种方式的代码对于人们来说简直无法理解，所以我认为它不是一个真正可行的方法。如果您有好的方法，请给我发 e-mail。<br /><br />我也希望能等到下述复杂条件被实现的一天。例如：<br /><br />其中a 、 b 和 c 是任意对象。<br /><br /></font>
				<font size="2">
						<strong>修改Thread 类<br /></strong>
						<br />同时支持抢占式和协作式线程的能力在某些服务器应用程序中是基本要求，尤其是在想使系统达到最高性能的情况下。我认为 Java 编程语言在简化线程模型上走得太远了，并且 Java 编程语言应支持 Posix/Solaris 的"绿色(green)线程"和"轻便(lightweight)进程"概念（在"（Taming Java Threads "第一章中讨论）。 这就是说，有些 Java 虚拟机的实现（例如在 NT 上的 Java 虚拟机）应在其内部仿真协作式进程，其它 Java 虚拟机应仿真抢占式线程。而且向 Java 虚拟机加入这些扩展是很容易的。<br /><br />一个 Java 的Thread 应始终是抢占式的。这就是说，一个 Java 编程语言的线程应像 Solaris 的轻便进程一样工作。 Runnable 接口可以用于定义一个 Solaris 式的"绿色线程"，此线程必需能把控制权转给运行在相同轻便进程中的其它绿色线程。<br /><br />例如，目前的语法：<br /><br />能有效地为Runnable 对象产生一个绿色线程，并把它绑定到由 Thread 对象代表的轻便进程中。这种实现对于现有代码是透明的，因为它的有效性和现有的完全一样。<br /><br />把Runnable 对象想成为绿色线程，使用这种方法，只需向 Thread 的构造函数传递几个 Runnable 对象，就可以扩展 Java 编程语言的现有语法，以支持在一个单一轻便线程有多个绿色线程。（绿色线程之间可以相互协作，但是它们可被运行在其它轻便进程 ( Thread 对象) 上的绿色进程( Runnable 对象) 抢占。）。例如，下面的代码会为每个 runnable 对象创建一个绿色线程，这些绿色线程会共享由 Thread 对象代表的轻便进程。<br /><br />现有的覆盖(override)Thread 对象并实现 run() 的习惯继续有效，但是它应映射到一个被绑定到一轻便进程的绿色线程。(在 Thread() 类中的缺省 run() 方法会在内部有效地创建第二个 Runnable 对象。)<br /><br /></font>
				<font size="2">
						<strong>线程间的协作<br /></strong>
						<br />应在语言中加入更多的功能以支持线程间的相互通信。目前，PipedInputStream 和 PipedOutputStream 类可用于这个目的。但是对于大多数应用程序，它们太弱了。我建议向 Thread 类加入下列函数： 增加一个 wait_for_start() 方法，它通常处于阻塞状态，直到一个线程的 run() 方法启动。(如果等待的线程在调用 run 之前被释放，这没有什么问题）。用这种方法，一个线程可以创建一个或多个辅助线程，并保证在创建线程继续执行操作之前，这些辅助线程会处于运行状态。 （向 Object 类）增加 $send (Object o) 和 Object=$receive() 方法，它们将使用一个内部阻断队列在线程之间传送对象。阻断队列应作为第一个 $send() 调用的副产品被自动创建。 $send() 调用会把对象加入队列。 $receive() 调用通常处于阻塞状态，直到有一个对象被加入队列，然后它返回此对象。这种方法中的变量应支持设定入队和出队的操作超时能力： $send (Object o, long timeout) 和 $receive (long timeout)。<br /><br /></font>
				<font size="2">
						<strong>对于读写锁的内部支持<br /></strong>
						<br />读写锁的概念应内置到 Java 编程语言中。读写器锁在"Taming Java Threads "（和其它地方）中有详细讨论，概括地说：一个读写锁支持多个线程同时访问一个对象，但是在同一时刻只有一个线程可以修改此对象，并且在访问进行时不能修改。读写锁的语法可以借用 synchronized 关键字：<br /><br />对于一个对象，应该只有在$writing 块中没有线程时，才支持多个线程进入 $reading 块。在进行读操作时，一个试图进入 $writing 块的线程会被阻断，直到读线程退出 $reading 块。 当有其它线程处于 $writing 块时，试图进入 $reading 或 $writing 块的线程会被阻断，直到此写线程退出 $writing 块。<br /><br />如果读和写线程都在等待，缺省情况下，读线程会首先进行。但是，可以使用$writer_priority 属性修改类的定义来改变这种缺省方式。如：<br />访问部分创建的对象应是非法的<br /><br />当前情况下，JLS 允许访问部分创建的对象。例如，在一个构造函数中创建的线程可以访问正被创建的对象，既使此对象没有完全被创建。下面代码的结果无法确定：<br /><br />设置x 为 -1 的线程可以和设置 x 为 0 的线程同时进行。所以，此时 x 的值无法预测。<br /><br />对此问题的一个解决方法是，在构造函数没有返回之前，对于在此构造函数中创建的线程，既使它的优先级比调用new 的线程高，也要禁止运行它的 run() 方法。<br /><br />这就是说，在构造函数返回之前，start() 请求必须被推迟。<br /><br />另外，Java 编程语言应可允许构造函数的同步。换句话说，下面的代码（在当前情况下是非法的）会象预期的那样工作：<br /><br />我认为第一种方法比第二种更简洁，但实现起来更为困难。<br /><br />volatile关键字应象预期的那样工作<br /><br />JLS 要求保留对于 volatile 操作的请求。大多数 Java 虚拟机都简单地忽略了这部分内容，这是不应该的。在多处理器的情况下，许多主机都出现了这种问题，但是它本应由 JLS 加以解决的。如果您对这方面感兴趣，马里兰大学的 Bill Pugh 正在致力于这项工作（请参阅参考资料 ）。<br /><br /></font>
				<font size="2">
						<strong>访问的问题<br /></strong>
						<br />如果缺少良好的访问控制，会使线程编程非常困难。大多数情况下，如果能保证线程只从同步子系统中调用，不必考虑线程安全(threadsafe)问题。我建议对 Java 编程语言的访问权限概念做如下限制；应精确使用 package 关键字来限制包访问权。我认为当缺省行为的存在是任何一种计算机语言的一个瑕疵，我对现在存在这种缺省权限感到很迷惑（而且这种缺省是"包(package)"级别的而不是"私有(private)"）。在其它方面，Java 编程语言都不提供等同的缺省关键字。虽然使用显式的 package 的限定词会破坏现有代码，但是它将使代码的可读性更强，并能消除整个类的潜在错误 (例如，如果访问权是由于错误被忽略，而不是被故意忽略)。 重新引入 private protected ，它的功能应和现在的 protected 一样，但是不应允许包级别的访问。 允许 private private 语法指定"实现的访问"对于所有外部对象是私有的，甚至是当前对象是的同一个类的。对于"."左边的唯一引用（隐式或显式）应是 this 。 扩展 public 的语法，以授权它可制定特定类的访问。例如，下面的代码应允许 Fred 类的对象可调用 some_method() ，但是对其它类的对象，这个方法应是私有的。<br /><br />这种建议不同于 C++ 的 "friend" 机制。 在 "friend" 机制中，它授权一个类访问另一个类的所有 私有部分。在这里，我建议对有限的方法集合进行严格控制的访问。用这种方法，一个类可以为另一个类定义一个接口，而这个接口对系统的其余类是不可见的。一个明显的变化是：<br /><br />除非域引用的是真正不变(immutable)的对象或static final 基本类型，否则所有域的定义应是 private 。对于一个类中域的直接访问违反了 OO 设计的两个基本规则：抽象和封装。从线程的观点来看，允许直接访问域只使对它进行非同步访问更容易一些。<br /><br />增加$property 关键字。带有此关键字的对象可被一个"bean 盒"应用程序访问，这个程序使用在 Class 类中定义的反射操作(introspection) API，否则与 private private 同效。 $property 属性可用在域和方法，这样现有的 JavaBean getter/setter 方法可以很容易地被定义为属性。<br /><br /><strong>不变性(immutability)</strong><br /><br />由于对不变对象的访问不需要同步，所以在多线程条件下，不变的概念（一个对象的值在创建后不可更改）是无价的。Java 编程言语中，对于不变性的实现不够严格，有两个原因：对于一个不变对象，在其被未完全创建之前，可以对它进行访问。这种访问对于某些域可以产生不正确的值。 对于恒定 (类的所有域都是 final) 的定义太松散。对于由 final 引用指定的对象，虽然引用本身不能改变，但是对象本身可以改变状态。<br /><br />第一个问题可以解决，不允许线程在构造函数中开始执行 (或者在构造函数返回之前不能执行开始请求)。<br /><br />对于第二个问题，通过限定final 修饰符指向恒定对象，可以解决此问题。这就是说，对于一个对象，只有所有的域是 final，并且所有引用的对象的域也都是 final，此对象才真正是恒定的。为了不打破现有代码，这个定义可以使用编译器加强，即只有一个类被显式标为不变时，此类才是不变类。方法如下：<br /><br />有了$immutable 修饰符后，在域定义中的 final 修饰符是可选的。<br /><br />最后，当使用内部类(inner class)后，在 Java 编译器中的一个错误使它无法可靠地创建不变对象。当一个类有重要的内部类时(我的代码常有)，编译器经常不正确地显示下列错误信息：<br /><br />既使空的 final 在每个构造函数中都有初始化，还是会出现这个错误信息。自从在 1.1 版本中引入内部类后，编译器中一直有这个错误。在此版本中（三年以后），这个错误依然存在。现在，该是改正这个错误的时候了。<br /><br /></font>
				<font size="2">
						<strong>对于类级域的实例级访问<br /></strong>
						<br />除了访问权限外，还有一个问题，即类级（静态）方法和实例（非静态）方法都能直接访问类级（静态）域。这种访问是非常危险的，因为实例方法的同步不会获取类级的锁，所以一个synchronized static 方法和一个 synchronized 方法还是能同时访问类的域。改正此问题的一个明显的方法是，要求在实例方法中只有使用 static 访问方法才能访问非不变类的 static 域。当然，这种要求需要编译器和运行时间检查。在这种规定下，下面的代码是非法的：<br /><br />由于f() 和 g() 可以并行运行，所以它们能同时改变 x 的值（产生不定的结果）。请记住，这里有两个锁： static 方法要求属于 Class 对象的锁，而非静态方法要求属于此类实例的锁。当从实例方法中访问非不变 static 域时，编译器应要求满足下面两个结构中的任意一个：<br /><br />或则，编译器应获得读/写锁的使用：<br /><br />另外一种方法是（这也是一种理想的 方法）-- 编译器应 自动 使用一个读/写锁来同步访问非不变 static 域，这样，程序员就不必担心这个问题。<br /><br /><strong>后台线程的突然结束</strong><br /><br />当所有的非后台线程终止后，后台线程都被突然结束。当后台线程创建了一些全局资源（例如一个数据库连接或一个临时文件），而后台线程结束时这些资源没有被关闭或删除就会导致问题。<br /><br />对于这个问题，我建议制定规则，使 Java 虚拟机在下列情况下不关闭应用程序：有任何非后台线程正在运行，或者： 有任何后台线程正在执行一个 synchronized 方法或 synchronized 代码块。<br /><br />后台线程在它执行完synchronized 块或 synchronized 方法后可被立即关闭。<br /><br /><strong>重新引入stop() 、 suspend() 和 resume() 关键字</strong><br /><br />由于实用原因这也许不可行，但是我希望不要废除stop() (在 Thread 和 ThreadGroup 中)。但是，我会改变 stop() 的语义，使得调用它时不会破坏已有代码。但是，关于 stop() 的问题，请记住，当线程终止后， stop() 将释放所有锁，这样可能潜在地使正在此对象上工作的线程进入一种不稳定（局部修改）的状态。由于停止的线程已释放它在此对象上的所有锁，所以这些对象无法再被访问。<br /><br />对于这个问题，可以重新定义stop() 的行为，使线程只有在不占有任何锁时才立即终止。如果它占据着锁，我建议在此线程释放最后一个锁后才终止它。可以使用一个和抛出异常相似的机制来实现此行为。被停止线程应设置一个标志，并且当退出所有同步块时立即测试此标志。如果设置了此标志，就抛出一个隐式的异常，但是此异常应不再能被捕捉并且当线程结束时不会产生任何输出。注意，微软的 NT 操作系统不能很好地处理一个外部指示的突然停止(abrupt)。（它不把 stop 消息通知动态连接库，所以可能导致系统级的资源漏洞。）这就是我建议使用类似异常的方法简单地导致 run() 返回的原因。<br /><br />与这种和异常类似的处理方法带来的实际问题是，你必需在每个synchronized 块后都插入代码来测试"stopped"标志。并且这种附加的代码会降低系统性能并增加代码长度。我想到的另外一个办法是使 stop() 实现一个"延迟的(lazy)"停止，在这种情况下，在下次调用 wait() 或 yield() 时才终止。我还想向 Thread 中加入一个 isStopped() 和 stopped() 方法（此时， Thread 将像 isInterrupted() 和 interrupted() 一样工作，但是会检测 "stop-requested"的状态)。这种方法不向第一种那样通用，但是可行并且不会产生过载。<br /><br />应把suspend() 和 resume() 方法放回到 Java 编程语言中，它们是很有用的，我不想被当成是幼儿园的小孩。由于它们可能产生潜在的危险（当被挂起时，一个线程可以占据一个锁）而去掉它们是没有道理的。请让我自己来决定是否使用它们。如果接收的线程正占据着锁，Sun 公司应该把它们作为调用 suspend() 的一个运行时间异常处理(run-time exception)；或者更好的方法是，延迟实际的挂起过程，直到线程释放所有的锁。<br /><br /><strong>被阻断的 I/O 应正确工作</strong><br /><br />应该能打断任何被阻断的操作，而不是只让它们wait() 和 sleep() 。我在" Taming Java Threads "的第二章中的 socket 部分讨论了此问题。但是现在，对于一个被阻断的 socket 上的 I/O 操作，打断它的唯一办法是关闭这个 socket，而没有办法打断一个被阻断的文件 I/O 操作。例如，一旦开始一个读请求并且进入阻断状态后，除非到它实际读出一些东西，否则线程一直出于阻断状态。既使关掉文件句柄也不能打断读操作。<br /><br />还有，程序应支持 I/O 操作的超时。所有可能出现阻断操作的对象（例如 InputStream 对象）也都应支持这种方法：<br /><br />这和 Socket 类的setSoTimeout(time) 方法是等价的。同样地，应该支持把超时作为参数传递到阻断的调用。<br /><br />ThreadGroup类<br /><br />ThreadGroup应该实现 Thread 中能够改变线程状态的所有方法。我特别想让它实现 join() 方法，这样我就可等待组中的所有线程的终止。<br /><br /><strong>总结</strong><br /><br />以上是我的建议。就像我在标题中所说的那样，如果我是国王...（哎）。我希望这些改变（或其它等同的方法）最终能被引入 Java 语言中。我确实认为 Java 语言是一种伟大的编程语言；但是我也认为 Java 的线程模型设计得还不够完善，这是一件很可惜的事情。但是，Java 编程语言正在演变，所以还有可提高的前景。<br /><br />参考资料本文是对 Taming Java Threads 的更新摘编。该书探讨了在 Java 语言中多线程编程的陷阱和问题，并提供了一个与线程相关的 Java 程序包来解决这些问题。 马里兰大学的 Bill Pugh 正在致力修改 JLS 来提高其线程模型。Bill 的提议并不如本文所推荐的那么广，他主要致力于让现有的线程模型以更为合理方式运行。更多信息可从 www.cs.umd.edu/~pugh/java/memoryModel/ 获得。 从 Sun 网站 可找到全部 Java 语言的规范。 要从一个纯技术角度来审视线程，参阅 Doug Lea 编著的 Concurrent Programming in Java: Design Principles and Patterns 第二版 。这是本很棒的书，但是它的风格是非常学术化的并不一定适合所有的读者。对《 Taming Java Threads 》是个很好的补充读物。 由 Scott Oaks 和 Henry Wong 编写的 Java Threads 比 Taming Java Threads 要轻量些，但是如果您从未编写过线程程序这本书更为适合。Oaks 和 Wong 同样实现了 Holub 提供的帮助类，而且看看对同一问题的不同解决方案总是有益的。 由 Bill Lewis 和 Daniel J. Berg　编写的 Threads Primer: A Guide to Multithreaded Programming 是对线程(不限于 Java)的很好入门介绍。 Java 线程的一些技术信息可在 Sun 网站 上找到。 在 "Multiprocessor Safety and Java" 中 Paul Jakubik 讨论了多线程系统的 SMP 问题 </font>
		</p>
<img src ="http://www.blogjava.net/errorfun/aggbug/86532.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/errorfun/" target="_blank">errorfun</a> 2006-12-09 13:50 <a href="http://www.blogjava.net/errorfun/articles/86532.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Java 线程应该注意的问题</title><link>http://www.blogjava.net/errorfun/articles/86531.html</link><dc:creator>errorfun</dc:creator><author>errorfun</author><pubDate>Sat, 09 Dec 2006 05:45:00 GMT</pubDate><guid>http://www.blogjava.net/errorfun/articles/86531.html</guid><wfw:comment>http://www.blogjava.net/errorfun/comments/86531.html</wfw:comment><comments>http://www.blogjava.net/errorfun/articles/86531.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/errorfun/comments/commentRss/86531.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/errorfun/services/trackbacks/86531.html</trackback:ping><description><![CDATA[
		<font size="2">
				<strong>1．同步对象的恒定性</strong>All java objects are references. </font>
		<p>
				<font size="2">　　对于局部变量和参数来说，java里面的int, float, double, boolean等基本数据类型，都在栈上。这些基本类型是无法同步的；java里面的对象（根对象是Object），全都在堆里，指向对象的reference在栈上。</font>
		</p>
		<p>
				<font size="2">　　java中的同步对象，实际上是对于reference所指的“对象地址”进行同步。</font>
		</p>
		<p>
				<font size="2">　　需要注意的问题是，千万不要对同步对象重新赋值。举个例子。</font>
		</p>
		<p>
				<font size="2">　　</font>
		</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; HEIGHT: 488px; BACKGROUND-COLOR: #eeeeee">
				<img id="Codehighlighter1_27_226_Open_Image" onclick="this.style.display='none'; Codehighlighter1_27_226_Open_Text.style.display='none'; Codehighlighter1_27_226_Closed_Image.style.display='inline'; Codehighlighter1_27_226_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_27_226_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_27_226_Closed_Text.style.display='none'; Codehighlighter1_27_226_Open_Image.style.display='inline'; Codehighlighter1_27_226_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> A </span>
				<span style="COLOR: #0000ff">implements</span>
				<span style="COLOR: #000000"> Runnable</span>
				<span id="Codehighlighter1_27_226_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_27_226_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　Object lock </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">new</span>
						<span style="COLOR: #000000"> Object();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_73_221_Open_Image" onclick="this.style.display='none'; Codehighlighter1_73_221_Open_Text.style.display='none'; Codehighlighter1_73_221_Closed_Image.style.display='inline'; Codehighlighter1_73_221_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_73_221_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_73_221_Closed_Text.style.display='none'; Codehighlighter1_73_221_Open_Image.style.display='inline'; Codehighlighter1_73_221_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> run()</span>
						<span id="Codehighlighter1_73_221_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_73_221_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_89_213_Open_Image" onclick="this.style.display='none'; Codehighlighter1_89_213_Open_Text.style.display='none'; Codehighlighter1_89_213_Closed_Image.style.display='inline'; Codehighlighter1_89_213_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_89_213_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_89_213_Closed_Text.style.display='none'; Codehighlighter1_89_213_Open_Image.style.display='inline'; Codehighlighter1_89_213_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　   </span>
								<span style="COLOR: #0000ff">for</span>
								<span style="COLOR: #000000">(<img src="http://www.blogjava.net/images/dot.gif" />)</span>
								<span id="Codehighlighter1_89_213_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.blogjava.net/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_89_213_Open_Text">
										<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_118_204_Open_Image" onclick="this.style.display='none'; Codehighlighter1_118_204_Open_Text.style.display='none'; Codehighlighter1_118_204_Closed_Image.style.display='inline'; Codehighlighter1_118_204_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_118_204_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_118_204_Closed_Text.style.display='none'; Codehighlighter1_118_204_Open_Image.style.display='inline'; Codehighlighter1_118_204_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　      </span>
										<span style="COLOR: #0000ff">synchronized</span>
										<span style="COLOR: #000000">(lock)</span>
										<span id="Codehighlighter1_118_204_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
												<img src="http://www.blogjava.net/images/dot.gif" />
										</span>
										<span id="Codehighlighter1_118_204_Open_Text">
												<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　      </span>
												<span style="COLOR: #008000">//</span>
												<span style="COLOR: #008000"> do something<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　      </span>
												<span style="COLOR: #008000">//</span>
												<span style="COLOR: #008000">
														<img src="http://www.blogjava.net/images/dot.gif" />
												</span>
												<span style="COLOR: #008000">
														<br />
														<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
												</span>
												<span style="COLOR: #000000">
														<br />
														<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　        lock </span>
												<span style="COLOR: #000000">=</span>
												<span style="COLOR: #000000"> </span>
												<span style="COLOR: #0000ff">new</span>
												<span style="COLOR: #000000"> Object(); 　<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />          }</span>
										</span>
										<span style="COLOR: #000000">
												<br />
												<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />       }</span>
								</span>
								<span style="COLOR: #000000"> 　　<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />   }</span>
						</span>
						<span style="COLOR: #000000"> 　　<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
		</div>
		<p>
				<font size="2"> 　　run函数里面的这段同步代码实际上是毫无意义的。因为每一次lock都给重新分配了新的对象的reference，每个线程都在新的reference同步。</font>
		</p>
		<p>
				<font size="2">　　大家可能觉得奇怪，怎么会举这么一个例子。因为我见过这样的代码，同步对象在其它的函数里被重新赋了新值。</font>
		</p>
		<p>
				<font size="2">　　这种问题很难查出来。</font>
		</p>
		<p>
				<font size="2">　　所以，一般应该把同步对象声明为final.</font>
		</p>
		<p>
				<font size="2">　　final Object lock = new Object();</font>
		</p>
		<p>
				<font size="2">　　使用Singleton Pattern 设计模式来获取同步对象，也是一种很好的选择。</font>
		</p>
		<p>
				<font size="2">　　<strong>2．如何放置共享数据</strong>实现线程，有两种方法，一种是继承Thread类，一种是实现Runnable接口。</font>
		</p>
		<p>
				<font size="2">　　上面举的例子，采用实现Runnable接口的方法。本文推荐这种方法。</font>
		</p>
		<p>
				<font size="2">　　首先，把需要共享的数据放在一个实现Runnable接口的类里面，然后，把这个类的实例传给多个Thread的构造方法。这样，新创建的多个Thread，都共同拥有一个Runnable实例，共享同一份数据。</font>
		</p>
		<p>
				<font size="2">　　如果采用继承Thread类的方法，就只好使用static静态成员了。如果共享的数据比较多，就需要大量的static静态成员，令程序数据结构混乱，难以扩展。这种情况应该尽量避免。</font>
		</p>
		<p>
				<font size="2">　　编写一段多线程代码，处理一个稍微复杂点的问题。两种方法的优劣，一试便知。</font>
		</p>
		<p>
				<font size="2">　　<strong>3．同步的粒度</strong>线程同步的粒度越小越好，即，线程同步的代码块越小越好。尽量避免用synchronized修饰符来声明方法。尽量使用synchronized(anObject)的方式，如果不想引入新的同步对象，使用synchronized(this)的方式。而且，synchronized代码块越小越好。</font>
		</p>
		<p>
				<font size="2">　　<strong>4．线程之间的通知</strong>这里使用“通知”这个词，而不用“通信”这个词，是为了避免词义的扩大化。</font>
		</p>
		<p>
				<font size="2">　　线程之间的通知，通过Object对象的wait()和notify() 或notifyAll() 方法实现。</font>
		</p>
		<p>
				<font size="2">　　下面用一个例子，来说明其工作原理：</font>
		</p>
		<p>
				<font size="2">　　假设有两个线程，A和B。共同拥有一个同步对象，lock。</font>
		</p>
		<p>
				<font size="2">　　1．首先，线程A通过synchronized(lock) 获得lock同步对象，然后调用lock.wait()函数，放弃lock同步对象，线程A停止运行，进入等待队列。</font>
		</p>
		<p>
				<font size="2">　　2．线程B通过synchronized(lock) 获得线程A放弃的lock同步对象，做完一定的处理，然后调用 lock.notify() 或者lock.notifyAll() 通知等待队列里面的线程A。</font>
		</p>
		<p>
				<font size="2">　　3．线程A从等待队列里面出来，进入ready队列，等待调度。</font>
		</p>
		<p>
				<font size="2">　　4．线程B继续处理，出了synchronized(lock)块之后，放弃lock同步对象。</font>
		</p>
		<p>
				<font size="2">　　5．线程A获得lock同步对象，继续运行。</font>
		</p>
		<p>
				<font size="2">　　例子代码如下：</font>
		</p>
		<p>
				<font size="2">　　</font>
		</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img id="Codehighlighter1_47_1321_Open_Image" onclick="this.style.display='none'; Codehighlighter1_47_1321_Open_Text.style.display='none'; Codehighlighter1_47_1321_Closed_Image.style.display='inline'; Codehighlighter1_47_1321_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_47_1321_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_47_1321_Closed_Text.style.display='none'; Codehighlighter1_47_1321_Open_Image.style.display='inline'; Codehighlighter1_47_1321_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> SharedResource </span>
				<span style="COLOR: #0000ff">implements</span>
				<span style="COLOR: #000000"> Runnable</span>
				<span id="Codehighlighter1_47_1321_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_47_1321_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　Object lock </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">new</span>
						<span style="COLOR: #000000"> Object();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_100_1321_Open_Image" onclick="this.style.display='none'; Codehighlighter1_100_1321_Open_Text.style.display='none'; Codehighlighter1_100_1321_Closed_Image.style.display='inline'; Codehighlighter1_100_1321_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_100_1321_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_100_1321_Closed_Text.style.display='none'; Codehighlighter1_100_1321_Open_Image.style.display='inline'; Codehighlighter1_100_1321_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000"> run()</span>
						<span id="Codehighlighter1_100_1321_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_100_1321_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　</span>
								<span style="COLOR: #008000">//</span>
								<span style="COLOR: #008000"> 获取当前线程的名称。</span>
								<span style="COLOR: #008000">
										<br />
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
								</span>
								<span style="COLOR: #000000">
										<br />
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　String threadName </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> Thread.currentThread().getName();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_206_1317_Open_Image" onclick="this.style.display='none'; Codehighlighter1_206_1317_Open_Text.style.display='none'; Codehighlighter1_206_1317_Closed_Image.style.display='inline'; Codehighlighter1_206_1317_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_206_1317_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_206_1317_Closed_Text.style.display='none'; Codehighlighter1_206_1317_Open_Image.style.display='inline'; Codehighlighter1_206_1317_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span>
								<span style="COLOR: #0000ff">if</span>
								<span style="COLOR: #000000">( “A”.equals(threadName))</span>
								<span id="Codehighlighter1_206_1317_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
										<img src="http://www.blogjava.net/images/dot.gif" />
								</span>
								<span id="Codehighlighter1_206_1317_Open_Text">
										<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_229_525_Open_Image" onclick="this.style.display='none'; Codehighlighter1_229_525_Open_Text.style.display='none'; Codehighlighter1_229_525_Closed_Image.style.display='inline'; Codehighlighter1_229_525_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_229_525_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_229_525_Closed_Text.style.display='none'; Codehighlighter1_229_525_Open_Image.style.display='inline'; Codehighlighter1_229_525_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span>
										<span style="COLOR: #0000ff">synchronized</span>
										<span style="COLOR: #000000">(lock)</span>
										<span id="Codehighlighter1_229_525_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
												<img src="http://www.blogjava.net/images/dot.gif" />
										</span>
										<span id="Codehighlighter1_229_525_Open_Text">
												<span style="COLOR: #000000">{ </span>
												<span style="COLOR: #008000">//</span>
												<span style="COLOR: #008000">线程A通过synchronized(lock) 获得lock同步对象</span>
												<span style="COLOR: #008000">
														<br />
														<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
												</span>
												<span style="COLOR: #000000">
														<br />
														<img id="Codehighlighter1_274_392_Open_Image" onclick="this.style.display='none'; Codehighlighter1_274_392_Open_Text.style.display='none'; Codehighlighter1_274_392_Closed_Image.style.display='inline'; Codehighlighter1_274_392_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
														<img id="Codehighlighter1_274_392_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_274_392_Closed_Text.style.display='none'; Codehighlighter1_274_392_Open_Image.style.display='inline'; Codehighlighter1_274_392_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span>
												<span style="COLOR: #0000ff">try</span>
												<span id="Codehighlighter1_274_392_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
														<img src="http://www.blogjava.net/images/dot.gif" />
												</span>
												<span id="Codehighlighter1_274_392_Open_Text">
														<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　System.out.println(“ A gives up lock.”);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　lock.wait(); </span>
														<span style="COLOR: #008000">//</span>
														<span style="COLOR: #008000"> 调用lock.wait()函数，放弃lock同步对象，<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　</span>
														<span style="COLOR: #008000">//</span>
														<span style="COLOR: #008000"> 线程A停止运行，进入等待队列。</span>
														<span style="COLOR: #008000">
																<br />
																<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
														</span>
														<span style="COLOR: #000000">
																<br />
																<img id="Codehighlighter1_422_426_Open_Image" onclick="this.style.display='none'; Codehighlighter1_422_426_Open_Text.style.display='none'; Codehighlighter1_422_426_Closed_Image.style.display='inline'; Codehighlighter1_422_426_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
																<img id="Codehighlighter1_422_426_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_422_426_Closed_Text.style.display='none'; Codehighlighter1_422_426_Open_Image.style.display='inline'; Codehighlighter1_422_426_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　}</span>
												</span>
												<span style="COLOR: #0000ff">catch</span>
												<span style="COLOR: #000000">(InterruptedException e)</span>
												<span id="Codehighlighter1_422_426_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
														<img src="http://www.blogjava.net/images/dot.gif" />
												</span>
												<span id="Codehighlighter1_422_426_Open_Text">
														<span style="COLOR: #000000">{ 　　}</span>
												</span>
												<span style="COLOR: #000000"> 　　</span>
												<span style="COLOR: #008000">//</span>
												<span style="COLOR: #008000"> 线程A重新获得lock同步对象之后，继续运行。</span>
												<span style="COLOR: #008000">
														<br />
														<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
												</span>
												<span style="COLOR: #000000">
														<br />
														<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　System.out.println(“ A got lock again and </span>
												<span style="COLOR: #0000ff">continue</span>
												<span style="COLOR: #000000"> to run.”);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />　　}</span>
										</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #008000">//</span>
										<span style="COLOR: #008000"> end of synchronized(lock) 　　} 　　if( “B”.equals(threadName)){</span>
										<span style="COLOR: #008000">
												<br />
												<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
										</span>
										<span style="COLOR: #000000">
												<br />
												<img id="Codehighlighter1_612_838_Open_Image" onclick="this.style.display='none'; Codehighlighter1_612_838_Open_Text.style.display='none'; Codehighlighter1_612_838_Closed_Image.style.display='inline'; Codehighlighter1_612_838_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
												<img id="Codehighlighter1_612_838_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_612_838_Closed_Text.style.display='none'; Codehighlighter1_612_838_Open_Image.style.display='inline'; Codehighlighter1_612_838_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span>
										<span style="COLOR: #0000ff">synchronized</span>
										<span style="COLOR: #000000">(lock)</span>
										<span id="Codehighlighter1_612_838_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
												<img src="http://www.blogjava.net/images/dot.gif" />
										</span>
										<span id="Codehighlighter1_612_838_Open_Text">
												<span style="COLOR: #000000">{</span>
												<span style="COLOR: #008000">//</span>
												<span style="COLOR: #008000">线程B通过synchronized(lock) 获得线程A放弃的lock同步对象</span>
												<span style="COLOR: #008000">
														<br />
														<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
												</span>
												<span style="COLOR: #000000">
														<br />
														<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　System.out.println(“B got lock.”);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　lock.notify(); </span>
												<span style="COLOR: #008000">//</span>
												<span style="COLOR: #008000">通知等待队列里面的线程A，进入ready队列，等待调度。<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　</span>
												<span style="COLOR: #008000">//</span>
												<span style="COLOR: #008000">线程B继续处理，出了synchronized(lock)块之后，放弃lock同步对象。</span>
												<span style="COLOR: #008000">
														<br />
														<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
												</span>
												<span style="COLOR: #000000">
														<br />
														<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　System.out.println(“B gives up lock.”);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />　　}</span>
										</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #008000">//</span>
										<span style="COLOR: #008000"> end of synchronized(lock)</span>
										<span style="COLOR: #008000">
												<br />
												<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
										</span>
										<span style="COLOR: #000000">
												<br />
												<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　</span>
										<span style="COLOR: #0000ff">boolean</span>
										<span style="COLOR: #000000"> hasLock </span>
										<span style="COLOR: #000000">=</span>
										<span style="COLOR: #000000"> Thread.holdsLock(lock); </span>
										<span style="COLOR: #008000">//</span>
										<span style="COLOR: #008000"> 检查B是否拥有lock同步对象。</span>
										<span style="COLOR: #008000">
												<br />
												<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
										</span>
										<span style="COLOR: #000000">
												<br />
												<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　System.out.println(“B has lock </span>
										<span style="COLOR: #000000">?</span>
										<span style="COLOR: #000000"> </span>
										<span style="COLOR: #000000">--</span>
										<span style="COLOR: #000000"> ” hasLock); </span>
										<span style="COLOR: #008000">//</span>
										<span style="COLOR: #008000"> false. 　　} 　　} 　　} 　　public class TestMain{</span>
										<span style="COLOR: #008000">
												<br />
												<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
										</span>
										<span style="COLOR: #000000">
												<br />
												<img id="Codehighlighter1_1060_1313_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1060_1313_Open_Text.style.display='none'; Codehighlighter1_1060_1313_Closed_Image.style.display='inline'; Codehighlighter1_1060_1313_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
												<img id="Codehighlighter1_1060_1313_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1060_1313_Closed_Text.style.display='none'; Codehighlighter1_1060_1313_Open_Image.style.display='inline'; Codehighlighter1_1060_1313_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</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">void</span>
										<span style="COLOR: #000000"> main()</span>
										<span id="Codehighlighter1_1060_1313_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
												<img src="http://www.blogjava.net/images/dot.gif" />
										</span>
										<span id="Codehighlighter1_1060_1313_Open_Text">
												<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　Runnable resource </span>
												<span style="COLOR: #000000">=</span>
												<span style="COLOR: #000000"> </span>
												<span style="COLOR: #0000ff">new</span>
												<span style="COLOR: #000000"> SharedResource();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　Thread A </span>
												<span style="COLOR: #000000">=</span>
												<span style="COLOR: #000000"> </span>
												<span style="COLOR: #0000ff">new</span>
												<span style="COLOR: #000000"> Thread(resource，”A”);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　A.start();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　</span>
												<span style="COLOR: #008000">//</span>
												<span style="COLOR: #008000"> 强迫主线程停止运行，以便线程A开始运行。</span>
												<span style="COLOR: #008000">
														<br />
														<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
												</span>
												<span style="COLOR: #000000">
														<br />
														<img id="Codehighlighter1_1195_1222_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1195_1222_Open_Text.style.display='none'; Codehighlighter1_1195_1222_Closed_Image.style.display='inline'; Codehighlighter1_1195_1222_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
														<img id="Codehighlighter1_1195_1222_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1195_1222_Closed_Text.style.display='none'; Codehighlighter1_1195_1222_Open_Image.style.display='inline'; Codehighlighter1_1195_1222_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　</span>
												<span style="COLOR: #0000ff">try</span>
												<span style="COLOR: #000000"> </span>
												<span id="Codehighlighter1_1195_1222_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
														<img src="http://www.blogjava.net/images/dot.gif" />
												</span>
												<span id="Codehighlighter1_1195_1222_Open_Text">
														<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />　　Thread.sleep(</span>
														<span style="COLOR: #000000">500</span>
														<span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_1252_1256_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1252_1256_Open_Text.style.display='none'; Codehighlighter1_1252_1256_Closed_Image.style.display='inline'; Codehighlighter1_1252_1256_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_1252_1256_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1252_1256_Closed_Text.style.display='none'; Codehighlighter1_1252_1256_Open_Image.style.display='inline'; Codehighlighter1_1252_1256_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />　　}</span>
												</span>
												<span style="COLOR: #0000ff">catch</span>
												<span style="COLOR: #000000">(InterruptedException e)</span>
												<span id="Codehighlighter1_1252_1256_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
														<img src="http://www.blogjava.net/images/dot.gif" />
												</span>
												<span id="Codehighlighter1_1252_1256_Open_Text">
														<span style="COLOR: #000000">{ 　　}</span>
												</span>
												<span style="COLOR: #000000"> 　　Thread B </span>
												<span style="COLOR: #000000">=</span>
												<span style="COLOR: #000000"> </span>
												<span style="COLOR: #0000ff">new</span>
												<span style="COLOR: #000000"> Thread(resource，”B”);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />　　B.start(); 　　}</span>
										</span>
										<span style="COLOR: #000000"> 　　}</span>
								</span>
								<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /></span>
						</span>
				</span>
		</div>
		<p>
				<br />
				<font size="2">　　 <strong>5．跨类的同步对象</strong>对于简单的问题，可以把访问共享资源的同步代码都放在一个类里面。</font>
		</p>
		<p>
				<font size="2">　　但是对于复杂的问题，我们需要把问题分为几个部分来处理，需要几个不同的类来处理问题。这时，就需要在不同的类中，共享同步对象。比如，在生产者和消费者之间共享同步对象，在读者和写者之间共享同步对象。</font>
		</p>
		<p>
				<font size="2">　　如何在不同的类中，共享同步对象。有几种方法实现，</font>
		</p>
		<p>
				<font size="2">　　（1）前面讲过的方法，使用static静态成员，（或者使用Singleton Pattern.）</font>
		</p>
		<p>
				<font size="2">　　（2）用参数传递的方法，把同步对象传递给不同的类。</font>
		</p>
		<p>
				<font size="2">　　（3）利用字符串常量的“原子性”。</font>
		</p>
		<p>
				<font size="2">　　对于第三种方法，这里做一下解释。一般来说，程序代码中的字符串常量经过编译之后，都具有唯一性，即，内存中不会存在两份相同的字符串常量。</font>
		</p>
		<p>
				<font size="2">　　（通常情况下，C ，C语言程序编译之后，也具有同样的特性。）</font>
		</p>
		<p>
				<font size="2">　　比如，我们有如下代码。</font>
		</p>
		<p>
				<font size="2">　　String A = “atom”;</font>
		</p>
		<p>
				<font size="2">　　String B = “atom”;</font>
		</p>
		<p>
				<font size="2">　　我们有理由认为，A和B指向同一个字符串常量。即，A==B。</font>
		</p>
		<p>
				<font size="2">　　注意，声明字符串变量的代码，不符合上面的规则。</font>
		</p>
		<p>
				<font size="2">　　String C= new String(“atom”);</font>
		</p>
		<p>
				<font size="2">　　String D = new String(“atom”);</font>
		</p>
		<p>
				<font size="2">　　这里的C和D的声明是字符串变量的声明，所以，C != D。</font>
		</p>
		<p>
				<font size="2">　　有了上述的认识，我们就可以使用字符串常量作为同步对象。</font>
		</p>
		<p>
				<font size="2">　　比如我们在不同的类中，使用synchronized(“myLock”), “myLock”.wait(),“myLock”.notify(), 这样的代码，就能够实现不同类之间的线程同步。</font>
		</p>
		<p>
				<font size="2">　　本文并不强烈推荐这种用法，只是说明，有这样一种方法存在。</font>
		</p>
		<p>
				<font size="2">　　本文推荐第二种方法，（2）用参数传递的方法，把同步对象传递给不同的类。</font>
		</p>
		<!--正文-->
<img src ="http://www.blogjava.net/errorfun/aggbug/86531.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/errorfun/" target="_blank">errorfun</a> 2006-12-09 13:45 <a href="http://www.blogjava.net/errorfun/articles/86531.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Java的垃圾回收机制详解和调优</title><link>http://www.blogjava.net/errorfun/articles/86528.html</link><dc:creator>errorfun</dc:creator><author>errorfun</author><pubDate>Sat, 09 Dec 2006 05:39:00 GMT</pubDate><guid>http://www.blogjava.net/errorfun/articles/86528.html</guid><wfw:comment>http://www.blogjava.net/errorfun/comments/86528.html</wfw:comment><comments>http://www.blogjava.net/errorfun/articles/86528.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/errorfun/comments/commentRss/86528.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/errorfun/services/trackbacks/86528.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">1.JVM的gc概述 <br /><br />　　gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存。java语言并不要求jvm有gc，也没有规定gc如何工作。不过常用的jvm都有gc，而且大多数gc都使用类似的算法管理内存和执行收集操作。</font>
		</p>
		<p>
				<font size="2">　　在充分理解了垃圾收集算法和执行过程后，才能有效的优化它的性能。有些垃圾收集专用于特殊的应用程序。比如，实时应用程序主要是为了避免垃圾收集中断，而大多数OLTP应用程序则注重整体效率。理解了应用程序的工作负荷和jvm支持的垃圾收集算法，便可以进行优化配置垃圾收集器。<br /><br />　　垃圾收集的目的在于清除不再使用的对象。gc通过确定对象是否被活动对象引用来确定是否收集该对象。gc首先要判断该对象是否是时候可以收集。两种常用的方法是引用计数和对象引用遍历。<br /><br />　　1.1.引用计数<br /><br />　　引用计数存储对特定对象的所有引用数，也就是说，当应用程序创建引用以及引用超出范围时，jvm必须适当增减引用数。当某对象的引用数为0时，便可以进行垃圾收集。<br /><br />　　1.2.对象引用遍历<br /><br />　　早期的jvm使用引用计数，现在大多数jvm采用对象引用遍历。对象引用遍历从一组对象开始，沿着整个对象图上的每条链接，递归确定可到达（reachable）的对象。如果某对象不能从这些根对象的一个（至少一个）到达，则将它作为垃圾收集。在对象遍历阶段，gc必须记住哪些对象可以到达，以便删除不可到达的对象，这称为标记（marking）对象。<br /><br />　　下一步，gc要删除不可到达的对象。删除时，有些gc只是简单的扫描堆栈，删除未标记的未标记的对象，并释放它们的内存以生成新的对象，这叫做清除（sweeping）。这种方法的问题在于内存会分成好多小段，而它们不足以用于新的对象，但是组合起来却很大。因此，许多gc可以重新组织内存中的对象，并进行压缩（compact），形成可利用的空间。<br /><br />　　为此，gc需要停止其他的活动活动。这种方法意味着所有与应用程序相关的工作停止，只有gc运行。结果，在响应期间增减了许多混杂请求。另外，更复杂的gc不断增加或同时运行以减少或者清除应用程序的中断。有的gc使用单线程完成这项工作，有的则采用多线程以增加效率。<br /><br />　　2.几种垃圾回收机制<br /><br />　　2.1.标记－清除收集器<br /><br />　　这种收集器首先遍历对象图并标记可到达的对象，然后扫描堆栈以寻找未标记对象并释放它们的内存。这种收集器一般使用单线程工作并停止其他操作。<br /><br />　　2.2.标记－压缩收集器<br /><br />　　有时也叫标记－清除－压缩收集器，与标记－清除收集器有相同的标记阶段。在第二阶段，则把标记对象复制到堆栈的新域中以便压缩堆栈。这种收集器也停止其他操作。<br /><br />　　2.3.复制收集器<br /><br />　　这种收集器将堆栈分为两个域，常称为半空间。每次仅使用一半的空间，jvm生成的新对象则放在另一半空间中。gc运行时，它把可到达对象复制到另一半空间，从而压缩了堆栈。这种方法适用于短生存期的对象，持续复制长生存期的对象则导致效率降低。<br /><br />　　2.4.增量收集器<br /><br />　　增量收集器把堆栈分为多个域，每次仅从一个域收集垃圾。这会造成较小的应用程序中断。<br /><br />　　2.5.分代收集器<br /><br />　　这种收集器把堆栈分为两个或多个域，用以存放不同寿命的对象。jvm生成的新对象一般放在其中的某个域中。过一段时间，继续存在的对象将获得使用期并转入更长寿命的域中。分代收集器对不同的域使用不同的算法以优化性能。<br /><br />　　2.6.并发收集器<br /><br />　　并发收集器与应用程序同时运行。这些收集器在某点上（比如压缩时）一般都不得不停止其他操作以完成特定的任务，但是因为其他应用程序可进行其他的后台操作，所以中断其他处理的实际时间大大降低。<br /><br />　　2.7.并行收集器<br /><br />　　并行收集器使用某种传统的算法并使用多线程并行的执行它们的工作。在多cpu机器上使用多线程技术可以显著的提高java应用程序的可扩展性。<br /><br />　　3.Sun HotSpot<br /><br />　　1.4.1 JVM堆大小的调整<br /><br />　　Sun HotSpot 1.4.1使用分代收集器，它把堆分为三个主要的域：新域、旧域以及永久域。Jvm生成的所有新对象放在新域中。一旦对象经历了一定数量的垃圾收集循环后，便获得使用期并进入旧域。在永久域中jvm则存储class和method对象。就配置而言，永久域是一个独立域并且不认为是堆的一部分。<br /><br />　　下面介绍如何控制这些域的大小。可使用-Xms和-Xmx 控制整个堆的原始大小或最大值。<br /><br />　　下面的命令是把初始大小设置为128M：<br /><br />　　java –Xms128m <br /><br />　　–Xmx256m为控制新域的大小，可使用-XX:NewRatio设置新域在堆中所占的比例。<br /><br />　　下面的命令把整个堆设置成128m，新域比率设置成3，即新域与旧域比例为1：3，新域为堆的1/4或32M：<br /><br />java –Xms128m –Xmx128m <br />–XX:NewRatio =3可使用-XX:NewSize和-XX:MaxNewsize设置新域的初始值和最大值。<br /><br />　　下面的命令把新域的初始值和最大值设置成64m: <br /><br />java –Xms256m –Xmx256m –Xmn64m<br /><br />　　永久域默认大小为4m。运行程序时，jvm会调整永久域的大小以满足需要。每次调整时，jvm会对堆进行一次完全的垃圾收集。<br /><br />　　使用-XX:MaxPerSize标志来增加永久域搭大小。在WebLogic Server应用程序加载较多类时，经常需要增加永久域的最大值。当jvm加载类时，永久域中的对象急剧增加，从而使jvm不断调整永久域大小。为了避免调整，可使用-XX:PerSize标志设置初始值。<br /><br />　　下面把永久域初始值设置成32m，最大值设置成64m。<br /><br />java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m<br /><br />　　默认状态下，HotSpot在新域中使用复制收集器。该域一般分为三个部分。第一部分为Eden，用于生成新的对象。另两部分称为救助空间，当Eden充满时，收集器停止应用程序，把所有可到达对象复制到当前的from救助空间，一旦当前的from救助空间充满，收集器则把可到达对象复制到当前的to救助空间。From和to救助空间互换角色。维持活动的对象将在救助空间不断复制，直到它们获得使用期并转入旧域。使用-XX:SurvivorRatio可控制新域子空间的大小。<br /><br />　　同NewRation一样，SurvivorRation规定某救助域与Eden空间的比值。比如，以下命令把新域设置成64m，Eden占32m，每个救助域各占16m：<br /><br />java -Xms256m -Xmx256m -Xmn64m -XX:SurvivorRation =2<br /><br />　　如前所述，默认状态下HotSpot对新域使用复制收集器，对旧域使用标记－清除－压缩收集器。在新域中使用复制收集器有很多意义，因为应用程序生成的大部分对象是短寿命的。理想状态下，所有过渡对象在移出Eden空间时将被收集。如果能够这样的话，并且移出Eden空间的对象是长寿命的，那么理论上可以立即把它们移进旧域，避免在救助空间反复复制。但是，应用程序不能适合这种理想状态，因为它们有一小部分中长寿命的对象。最好是保持这些中长寿命的对象并放在新域中，因为复制小部分的对象总比压缩旧域廉价。为控制新域中对象的复制，可用-XX:TargetSurvivorRatio控制救助空间的比例（该值是设置救助空间的使用比例。如救助空间位1M，该值50表示可用500K）。该值是一个百分比，默认值是50。当较大的堆栈使用较低的sruvivorratio时，应增加该值到80至90，以更好利用救助空间。用-XX:maxtenuring threshold可控制上限。<br /><br />　　为放置所有的复制全部发生以及希望对象从eden扩展到旧域，可以把MaxTenuring Threshold设置成0。设置完成后，实际上就不再使用救助空间了，因此应把SurvivorRatio设成最大值以最大化Eden空间，设置如下：<br /><br />java … -XX:MaxTenuringThreshold=0 –XX:SurvivorRatio＝50000 …<br /><br />　　4.BEA JRockit JVM的使用<br /><br />　　Bea WebLogic 8.1使用的新的JVM用于Intel平台。在Bea安装完毕的目录下可以看到有一个类似于jrockit81sp1_141_03的文件夹。这就是Bea新JVM所在目录。不同于HotSpot把Java字节码编译成本地码，它预先编译成类。JRockit还提供了更细致的功能用以观察JVM的运行状态，主要是独立的GUI控制台（只能适用于使用Jrockit才能使用jrockit81sp1_141_03自带的console监控一些cpu及memory参数）或者WebLogic Server控制台。<br /><br />　　Bea JRockit JVM支持4种垃圾收集器：<br /><br />　　4.1.1.分代复制收集器 <br /><br />　　它与默认的分代收集器工作策略类似。对象在新域中分配，即JRockit文档中的nursery。这种收集器最适合单cpu机上小型堆操作。<br /><br />　　4.1.2.单空间并发收集器<br /><br />　　该收集器使用完整堆，并与背景线程共同工作。尽管这种收集器可以消除中断，但是收集器需花费较长的时间寻找死对象，而且处理应用程序时收集器经常运行。如果处理器不能应付应用程序产生的垃圾，它会中断应用程序并关闭收集。<br /><br />　　分代并发收集器 这种收集器在护理域使用排它复制收集器，在旧域中则使用并发收集器。由于它比单空间共同发生收集器中断频繁，因此它需要较少的内存，应用程序的运行效率也较高，注意，过小的护理域可以导致大量的临时对象被扩展到旧域中。这会造成收集器超负荷运作，甚至采用排它性工作方式完成收集。<br /><br />　　4.1.3.并行收集器<br /><br />　　该收集器也停止其他进程的工作，但使用多线程以加速收集进程。尽管它比其他的收集器易于引起长时间的中断，但一般能更好的利用内存，程序效率也较高。<br /><br />　　默认状态下，JRockit使用分代并发收集器。要改变收集器，可使用-Xgc:&lt;gc_name&gt;，对应四个收集器分别为gencopy，singlecon，gencon以及parallel。可使用-Xms和-Xmx设置堆的初始大小和最大值。要设置护理域，则使用-Xns:java –jrockit –Xms512m –Xmx512m –Xgc:gencon –Xns128m…尽管JRockit支持-verbose:gc开关，但它输出的信息会因收集器的不同而异。JRockit还支持memory、load和codegen的输出。<br /><br />　　注意 ：如果 使用JRockit JVM的话还可以使用WLS自带的console（C:\bea\jrockit81sp1_141_03\bin下）来监控一些数据，如cpu，memery等。要想能构监控必须在启动服务时startWeblogic.cmd中加入－Xmanagement参数。<br /><br />　　5.如何从JVM中获取信息来进行调整<br /><br />　　-verbose.gc开关可显示gc的操作内容。打开它，可以显示最忙和最空闲收集行为发生的时间、收集前后的内存大小、收集需要的时间等。打开-xx:+ printgcdetails开关，可以详细了解gc中的变化。打开-XX: + PrintGCTimeStamps开关，可以了解这些垃圾收集发生的时间，自jvm启动以后以秒计量。最后，通过-xx: + PrintHeapAtGC开关了解堆的更详细的信息。为了了解新域的情况，可以通过-XX:=PrintTenuringDistribution开关了解获得使用期的对象权。<br /><br />　　6.Pdm系统JVM调整<br /><br />　　6.1.服务器：前提内存1G 单CPU<br /><br />　　可通过如下参数进行调整：－server 启用服务器模式（如果CPU多，服务器机建议使用此项）<br /><br />　　－Xms,－Xmx一般设为同样大小。 800m<br /><br />　　－Xmn 是将NewSize与MaxNewSize设为一致。320m<br /><br />　　－XX:PerSize 64m<br /><br />　　－XX:NewSize 320m 此值设大可调大新对象区，减少Full GC次数<br /><br />　　－XX:MaxNewSize 320m<br /><br />　　－XX:NewRato NewSize设了可不设。<br /><br />　　－XX: SurvivorRatio <br /><br />　　－XX:userParNewGC 可用来设置并行收集 <br /><br />　　－XX:ParallelGCThreads 可用来增加并行度 <br /><br />　　－XXUseParallelGC 设置后可以使用并行清除收集器<br /><br />　　－XX：UseAdaptiveSizePolicy 与上面一个联合使用效果更好，利用它可以自动优化新域大小以及救助空间比值<br /><br />　　6.2.客户机：通过在JNLP文件中设置参数来调整客户端JVM<br /><br />　　JNLP中参数：initial-heap-size和max-heap-size<br /><br />　　这可以在framework的RequestManager中生成JNLP文件时加入上述参数，但是这些值是要求根据客户机的硬件状态变化的（如客户机的内存大小等）。建议这两个参数值设为客户机可用内存的60％（有待测试）。为了在动态生成JNLP时以上两个参数值能够随客户机不同而不同，可靠虑获得客户机系统信息并将这些嵌到首页index.jsp中作为连接请求的参数。<br /><br />　　在设置了上述参数后可以通过Visualgc 来观察垃圾回收的一些参数状态，再做相应的调整来改善性能。一般的标准是减少fullgc的次数，最好硬件支持使用并行垃圾回收（要求多CPU）。 </font>
		</p>
<img src ="http://www.blogjava.net/errorfun/aggbug/86528.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/errorfun/" target="_blank">errorfun</a> 2006-12-09 13:39 <a href="http://www.blogjava.net/errorfun/articles/86528.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]探讨JAVA内存泄漏原因和检测工具</title><link>http://www.blogjava.net/errorfun/articles/86527.html</link><dc:creator>errorfun</dc:creator><author>errorfun</author><pubDate>Sat, 09 Dec 2006 05:19:00 GMT</pubDate><guid>http://www.blogjava.net/errorfun/articles/86527.html</guid><wfw:comment>http://www.blogjava.net/errorfun/comments/86527.html</wfw:comment><comments>http://www.blogjava.net/errorfun/articles/86527.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/errorfun/comments/commentRss/86527.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/errorfun/services/trackbacks/86527.html</trackback:ping><description><![CDATA[原文出处：<a href="http://dev2dev.bea.com/pub/a/2005/06/memory_leaks.html" s_oidt="0" s_oid="http://dev2dev.bea.com/pub/a/2005/06/memory_leaks.html"><font color="#000066" size="3">http://dev2dev.bea.com/pub/a/2005/06/memory_leaks.html<br /></font></a><br />垃圾收集器的作用<br />        虽然垃圾收集器处理了大多数内存管理问题，从而使编程人员的生活变得更轻松了，但是编程人员还是可能犯错而导致出现内存问题。简单地说，GC循环地跟踪所有来自“根”对象（堆栈对象、静态对象、JNI句柄指向的对象，诸如此类）的引用，并将所有它所能到达的对象标记为活动的。程序只可以操纵这些对象；其他的对象都被删除了。因为GC使程序不可能到达已被删除的对象，这么做就是安全的。 
<p><font size="3">　　虽然内存管理可以说是自动化的，但是这并不能使编程人员免受思考内存管理问题之苦。例如，分配（以及释放）内存总会有开销，虽然这种开销对编程人员来说是不可见的。创建了太多对象的程序将会比完成同样的功能而创建的对象却比较少的程序更慢一些（在其他条件相同的情况下）。</font></p><p><font size="3">　　而且，与本文更为密切相关的是，如果忘记“释放”先前分配的内存，就可能造成内存泄漏。如果程序保留对永远不再使用的对象的引用，这些对象将会占用并耗尽内存，这是因为自动化的垃圾收集器无法证明这些对象将不再使用。正如我们先前所说的，如果存在一个对对象的引用，对象就被定义为活动的，因此不能删除。为了确保能回收对象占用的内存，编程人员必须确保该对象不能到达。这通常是通过将对象字段设置为null或者从集合(collection)中移除对象而完成的。但是，注意，当局部变量不再使用时，没有必要将其显式地设置为null。对这些变量的引用将随着方法的退出而自动清除。</font></p><p><font size="3">　　概括地说，这就是内存托管语言中的内存泄漏产生的主要原因：保留下来却永远不再使用的对象引用。</font></p><p><font size="3">典型泄漏</font></p><p><font size="3">　　既然我们知道了在Java中确实有可能发生内存泄漏，就让我们来看一些典型的内存泄漏及其原因。</font></p><p><font size="3">全局集合</font></p><p><font size="3">　　在大的应用程序中有某种全局的数据储存库是很常见的，例如一个JNDI树或一个会话表。在这些情况下，必须注意管理储存库的大小。必须有某种机制从储存库中移除不再需要的数据。</font></p><p><font size="3">　　这可能有多种方法，但是最常见的一种是周期性运行的某种清除任务。该任务将验证储存库中的数据，并移除任何不再需要的数据。</font></p><p><font size="3">　　另一种管理储存库的方法是使用反向链接(referrer)计数。然后集合负责统计集合中每个入口的反向链接的数目。这要求反向链接告诉集合何时会退出入口。当反向链接数目为零时，该元素就可以从集合中移除了。</font></p><p><font size="3">缓存</font></p><p><font size="3">　　缓存是一种数据结构，用于快速查找已经执行的操作的结果。因此，如果一个操作执行起来很慢，对于常用的输入数据，就可以将操作的结果缓存，并在下次调用该操作时使用缓存的数据。</font></p><p><font size="3">　　缓存通常都是以动态方式实现的，其中新的结果是在执行时添加到缓存中的。典型的算法是：</font></p><p><font size="3">检查结果是否在缓存中，如果在，就返回结果。 <br />如果结果不在缓存中，就进行计算。 <br />将计算出来的结果添加到缓存中，以便以后对该操作的调用可以使用。 <br />　　该算法的问题（或者说是潜在的内存泄漏）出在最后一步。如果调用该操作时有相当多的不同输入，就将有相当多的结果存储在缓存中。很明显这不是正确的方法。</font></p><p><font size="3">　　为了预防这种具有潜在破坏性的设计，程序必须确保对于缓存所使用的内存容量有一个上限。因此，更好的算法是：</font></p><p><font size="3">检查结果是否在缓存中，如果在，就返回结果。 <br />如果结果不在缓存中，就进行计算。 <br />如果缓存所占的空间过大，就移除缓存最久的结果。 <br />将计算出来的结果添加到缓存中，以便以后对该操作的调用可以使用。 <br />　　通过始终移除缓存最久的结果，我们实际上进行了这样的假设：在将来，比起缓存最久的数据，最近输入的数据更有可能用到。这通常是一个不错的假设。</font></p><p><font size="3">　　新算法将确保缓存的容量处于预定义的内存范围之内。确切的范围可能很难计算，因为缓存中的对象在不断变化，而且它们的引用包罗万象。为缓存设置正确的大小是一项非常复杂的任务，需要将所使用的内存容量与检索数据的速度加以平衡。</font></p><p><font size="3">　　解决这个问题的另一种方法是使用java.lang.ref.SoftReference类跟踪缓存中的对象。这种方法保证这些引用能够被移除，如果虚拟机的内存用尽而需要更多堆的话。</font></p><p><font size="3">ClassLoader</font></p><p><font size="3">　　Java ClassLoader结构的使用为内存泄漏提供了许多可乘之机。正是该结构本身的复杂性使ClassLoader在内存泄漏方面存在如此多的问题。ClassLoader的特别之处在于它不仅涉及“常规”的对象引用，还涉及元对象引用，比如：字段、方法和类。这意味着只要有对字段、方法、类或ClassLoader的对象的引用，ClassLoader就会驻留在JVM中。因为ClassLoader本身可以关联许多类及其静态字段，所以就有许多内存被泄漏了。</font></p><p><font size="3">确定泄漏的位置</font></p><p><font size="3">　　通常发生内存泄漏的第一个迹象是：在应用程序中出现了OutOfMemoryError。这通常发生在您最不愿意它发生的生产环境中，此时几乎不能进行调试。有可能是因为测试环境运行应用程序的方式与生产系统不完全相同，因而导致泄漏只出现在生产中。在这种情况下，需要使用一些开销较低的工具来监控和查找内存泄漏。还需要能够无需重启系统或修改代码就可以将这些工具连接到正在运行的系统上。可能最重要的是，当进行分析时，需要能够断开工具而保持系统不受干扰。</font></p><p><font size="3">　　虽然OutOfMemoryError通常都是内存泄漏的信号，但是也有可能应用程序确实正在使用这么多的内存；对于后者，或者必须增加JVM可用的堆的数量，或者对应用程序进行某种更改，使它使用较少的内存。但是，在许多情况下，OutOfMemoryError都是内存泄漏的信号。一种查明方法是不间断地监控GC的活动，确定内存使用量是否随着时间增加。如果确实如此，就可能发生了内存泄漏。</font></p><p><font size="3">详细输出</font></p><p><font size="3">　　有许多监控垃圾收集器活动的方法。而其中使用最广泛的可能是使用-Xverbose:gc选项启动JVM，并观察输出。</font></p><p><font size="3">[memory ] 10.109-10.235: GC 65536K-&gt;16788K (65536K), 126.000 ms <br />　箭头后面的值（本例中是16788K）是垃圾收集所使用的堆的容量。</font></p><p><font size="3">控制台</font></p><p><font size="3">　　查看连续不断的GC的详细统计信息的输出将是非常乏味的。幸好有这方面的工具。JRockit Management Console可以显示堆使用量的图示。借助于该图，可以很容易地看出堆使用量是否随时间增加。</font></p><p><font size="3"><img style="WIDTH: 519px; HEIGHT: 325px" height="309" alt="" hspace="0" src="http://dev2dev.bea.com/images/2005/06/mem_leak_002.gif" width="400" align="baseline" border="0" /></font></p><p><font size="3">图1. JRockit Management Console</font></p><p><font size="3">　　甚至可以配置该管理控制台，以便如果发生堆使用量过大的情况（或基于其他的事件），控制台能够向您发送电子邮件。这明显使内存泄漏的查看变得更容易了。</font></p><p><font size="3">内存泄漏检测工具</font></p><p><font size="3">　　还有其他的专门进行内存泄漏检测的工具。JRockit Memory Leak Detector可以用来查看内存泄漏，并可以更深入地查出泄漏的根源。这个强大的工具是紧密集成到JRockit JVM中的，其开销非常小，对虚拟机的堆的访问也很容易。</font></p><p><font size="3">专业工具的优点</font></p><p><font size="3">　　一旦知道确实发生了内存泄漏，就需要更专业的工具来查明为什么会发生泄漏。JVM自己是不会告诉您的。这些专业工具从JVM获得内存系统信息的方法基本上有两种：JVMTI和字节码技术(byte code instrumentation)。Java虚拟机工具接口(Java Virtual Machine Tools Interface，JVMTI)及其前身Java虚拟机监视程序接口(Java Virtual Machine Profiling Interface，JVMPI)是外部工具与JVM通信并从JVM收集信息的标准化接口。字节码技术是指使用探测器处理字节码以获得工具所需的信息的技术。</font></p><p><font size="3">　　对于内存泄漏检测来说，这两种技术有两个缺点，这使它们不太适合用于生产环境。首先，它们在内存占用和性能降低方面的开销不可忽略。有关堆使用量的信息必须以某种方式从JVM导出，并收集到工具中进行处理。这意味着要为工具分配内存。信息的导出也影响了JVM的性能。例如，当收集信息时，垃圾收集器将运行得比较慢。另外一个缺点是需要始终将工具连在JVM上。这是不可能的：将工具连在一个已经启动的JVM上，进行分析，断开工具，并保持JVM运行。</font></p><p><font size="3">　　因为JRockit Memory Leak Detector是集成到JVM中的，就没有这两个缺点了。首先，许多处理和分析工作是在JVM内部进行的，所以没有必要转换或重新创建任何数据。处理还可以背负(piggyback)在垃圾收集器本身上而进行，这意味着提高了速度。其次，只要JVM是使用-Xmanagement选项（允许通过远程JMX接口监控和管理JVM）启动的，Memory Leak Detector就可以与运行中的JVM进行连接或断开。当该工具断开时，没有任何东西遗留在JVM中，JVM又将以全速运行代码，正如工具连接之前一样。</font></p><p><font size="3">趋势分析</font></p><p><font size="3">　　让我们深入地研究一下该工具以及它是如何用来跟踪内存泄漏的。在知道发生内存泄漏之后，第一步是要弄清楚泄漏了什么数据--哪个类的对象引起了泄漏？JRockit Memory Leak Detector是通过在每次垃圾收集时计算每个类的现有对象的数目来实现这一步的。如果特定类的对象数目随时间而增长（“增长率”），就可能发生了内存泄漏。 </font></p><p><font size="3"><img style="WIDTH: 518px; HEIGHT: 148px" height="174" alt="" hspace="0" src="http://dev2dev.bea.com/images/2005/06/mem_leak_003.gif" width="400" align="baseline" border="0" /><br />图2. Memory Leak Detector的趋势分析视图</font></p><p><font size="3">　　因为泄漏可能像细流一样非常小，所以趋势分析必须运行很长一段时间。在短时间内，可能会发生一些类的局部增长，而之后它们又会跌落。但是趋势分析的开销很小（最大开销也不过是在每次垃圾收集时将数据包由JRockit发送到Memory Leak Detector）。开销不应该成为任何系统的问题——即使是一个全速运行的生产中的系统。</font></p><p><font size="3">　　起初数目会跳跃不停，但是一段时间之后它们就会稳定下来，并显示出哪些类的数目在增长。</font></p><p><font size="3">找出根本原因</font></p><p><font size="3">　　有时候知道是哪些类的对象在泄漏就足以说明问题了。这些类可能只用于代码中的非常有限的部分，对代码进行一次快速检查就可以显示出问题所在。遗憾地是，很有可能只有这类信息还并不够。例如，常见到泄漏出在类java.lang.String的对象上，但是因为字符串在整个程序中都使用，所以这并没有多大帮助。</font></p><p><font size="3">　　我们想知道的是，另外还有哪些对象与泄漏对象关联？在本例中是String。为什么泄漏的对象还存在？哪些对象保留了对这些对象的引用？但是能列出的所有保留对String的引用的对象将会非常多，以至于没有什么实际用处。为了限制数据的数量，可以将数据按类分组，以便可以看出其他哪些对象的类与泄漏对象(String)关联。例如，String在Hashtable中是很常见的，因此我们可能会看到与String关联的Hashtable数据项对象。由Hashtable数据项倒推，我们最终可以找到与这些数据项有关的Hashtable对象以及String（如图3所示）。 </font></p><p><font size="3"><img style="WIDTH: 537px; HEIGHT: 244px" height="224" alt="" hspace="0" src="http://dev2dev.bea.com/images/2005/06/mem_leak_005.gif" width="400" align="baseline" border="0" /><br />图3. 在工具中看到的类型图的示例视图</font></p><p><font size="3">倒推</font></p><p><font size="3">　　因为我们仍然是以类的对象而不是单独的对象来看待对象，所以我们不知道是哪个Hashtable在泄漏。如果我们可以弄清楚系统中所有的Hashtable都有多大，我们就可以假定最大的Hashtable就是正在泄漏的那一个（因为随着时间的流逝它会累积泄漏而增长得相当大）。因此，一份有关所有Hashtable对象以及它们引用了多少数据的列表，将会帮助我们指出造成泄漏的确切Hashtabl。 </font></p><p><font size="3"><img style="WIDTH: 463px; HEIGHT: 112px" height="118" alt="" hspace="0" src="http://dev2dev.bea.com/images/2005/06/mem_leak_006.gif" width="400" align="baseline" border="0" /><br />图4. 界面：Hashtable对象以及它们所引用数据的数量的列表</font></p><p><font size="3">　　对对象引用数据数目的计算开销非常大（需要以该对象作为根遍历引用图），如果必须对许多对象都这么做，将会花很多时间。如果了解一点Hashtable的内部实现原理就可以找到一条捷径。Hashtable的内部有一个Hashtable数据项的数组。该数组随着Hashtable中对象数目的增长而增长。因此，为找出最大的Hashtable，我们只需找出引用Hashtable数据项的最大数组。这样要快很多。 </font></p><p><img style="WIDTH: 460px; HEIGHT: 114px" height="114" alt="" hspace="0" src="http://dev2dev.bea.com/images/2005/06/mem_leak_007.gif" width="400" align="baseline" border="0" /><br /><font size="3">图5. 界面：最大的Hashtable数据项数组及其大小的清单</font></p><p><font size="3">更进一步</font></p><p><font size="3">　　当找到发生泄漏的Hashtable实例时，我们可以看到其他哪些实例在引用该Hashtable，并倒推回去看看是哪个Hashtable在泄漏。</font></p><p><font size="3"><img style="WIDTH: 472px; HEIGHT: 51px" height="48" alt="" hspace="0" src="http://dev2dev.bea.com/images/2005/06/mem_leak_009.gif" width="400" align="baseline" border="0" /><br />图 6. 这就是工具中的实例图</font></p><p><font size="3">　　例如，该Hashtable可能是由MyServer类型的对象在名为activeSessions的字段中引用的。这种信息通常就足以查找源代码以定位问题所在了。 </font></p><p><font size="3"><img style="WIDTH: 458px; HEIGHT: 133px" height="137" alt="" hspace="0" src="http://dev2dev.bea.com/images/2005/06/mem_leak_010.gif" width="400" align="baseline" border="0" /><br />图7. 检查对象以及它对其他对象的引用</font></p><p><font size="3">找出分配位置</font></p><p><font size="3">　　当跟踪内存泄漏问题时，查看对象分配到哪里是很有用的。只知道它们如何与其他对象相关联（即哪些对象引用了它们）是不够的，关于它们在何处创建的信息也很有用。当然了，您并不想创建应用程序的辅助构件，以打印每次分配的堆栈跟踪(stack trace)。您也不想仅仅为了跟踪内存泄漏而在运行应用程序时将一个分析程序连接到生产环境中。</font></p><p><font size="3">　　借助于JRockit Memory Leak Detector，应用程序中的代码可以在分配时进行动态添加，以创建堆栈跟踪。这些堆栈跟踪可以在工具中进行累积和分析。只要不启用就不会因该功能而产生成本，这意味着随时可以进行分配跟踪。当请求分配跟踪时，JRockit 编译器动态插入代码以监控分配，但是只针对所请求的特定类。更好的是，在进行数据分析时，添加的代码全部被移除，代码中没有留下任何会引起应用程序性能降低的更改。 </font></p><p><font size="3"><img style="WIDTH: 439px" height="126" alt="" hspace="0" src="http://dev2dev.bea.com/images/2005/06/mem_leak_011.gif" width="400" align="baseline" border="0" /><br />图8. 示例程序执行期间String的分配的堆栈跟踪</font></p><p><font size="3">结束语</font></p><p><font size="3">　　内存泄漏是难以发现的。本文重点介绍了几种避免内存泄漏的最佳实践，包括要始终记住在数据结构中所放置的内容，以及密切监控内存使用量以发现突然的增长。</font></p><p><font size="3">　　我们都已经看到了JRockit Memory Leak Detector是如何用于生产中的系统以跟踪内存泄漏的。该工具使用一种三步式的方法来找出泄漏。首先，进行趋势分析，找出是哪个类的对象在泄漏。接下来，看看有哪些其他的类与泄漏的类的对象相关联。最后，进一步研究单个对象，看看它们是如何互相关联的。也有可能对系统中所有对象分配进行动态的堆栈跟踪。这些功能以及该工具紧密集成到JVM中的特性使您可以以一种安全而强大的方式跟踪内存泄漏并进行修复。</font></p><p><font size="3">参考资料</font></p><p><font size="3"><a href="http://dev2dev.bea.com/wljrockit/tools.html"><font color="#000066">JRockit工具下载</font></a><br /><a href="http://e-docs.bea.com/wljrockit/docs50/index.html"><font color="#000066">BEA JRockit 5.0说明文档</font></a><br /><a href="http://dev2dev.bea.com/pub/a/2005/02/jrockit5_new_features.html"><font color="#000066">JRockit 5.0中的新功能和新工具</font></a><br /><a href="http://dev2dev.bea.com/wljrockit/"><font color="#000066">BEA JRockit DevCenter <br /></font></a></font></p><img src ="http://www.blogjava.net/errorfun/aggbug/86527.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/errorfun/" target="_blank">errorfun</a> 2006-12-09 13:19 <a href="http://www.blogjava.net/errorfun/articles/86527.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Eclipse 启动运行速度调优</title><link>http://www.blogjava.net/errorfun/articles/86510.html</link><dc:creator>errorfun</dc:creator><author>errorfun</author><pubDate>Sat, 09 Dec 2006 02:30:00 GMT</pubDate><guid>http://www.blogjava.net/errorfun/articles/86510.html</guid><wfw:comment>http://www.blogjava.net/errorfun/comments/86510.html</wfw:comment><comments>http://www.blogjava.net/errorfun/articles/86510.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/errorfun/comments/commentRss/86510.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/errorfun/services/trackbacks/86510.html</trackback:ping><description><![CDATA[
		<div class="posttitle">
				<font size="2">Eclipse 启动运行速度调优</font>
		</div>
		<p>
				<font size="2">提高 JAVA IDE 的性能的JVM开关 <br />Submitted by 小天蝎 on 2005, August 18, 2:45 PM. integration <br />我的本本是p4 1.8G的dell c640 内存1G，eclipse 3.1 + myeclipse 4.0m2 速度还不错。</font>
		</p>
		<p>
				<font size="2">运行参数如下：<br />eclipse.exe -vmargs -Xverify:none -XX:+UseParallelGC -XX:PermSize=20M</font>
		</p>
		<p>
				<font size="2">－－－－－－－－－－－－－－</font>
		</p>
		<p>
				<font size="2">JVM 提供了各种用于调整内存分配和垃圾回收行为的标准开关和非标准开关。其中一些设置可以提高 JAVA IDE 的性能。 <br />注意，由于 -X （尤其是 -XX JVM）开关通常是 JVM 或 JVM 供应商特定的，本部分介绍的开关可用于 Sun Microsystems J2SE 1.4.2。</font>
		</p>
		<p>
				<font size="2">以下设置在大多数系统上将产生比工厂更好的设置性能。 <br />-vmargs - 表示将后面的所有参数直接传递到所指示的 Java VM。</font>
		</p>
		<p>
				<font size="2">-Xverify:none - 此开关关闭Java字节码验证，从而加快了类装入的速度，并使得在仅为验证目的而启动的过程中无需装入类。此开关缩短了启动时间，因此没有理由不使用它。 </font>
		</p>
		<p>
				<font size="2">-Xms24m - 此设置指示 Java 虚拟机将其初始堆大小设置为 24 MB。通过指示 JVM 最初应分配给堆的内存数量，可以使 JVM 不必在 IDE 占用较多内存时增加堆大小。 </font>
		</p>
		<p>
				<font size="2">-Xmx96m - 此设置指定 Java 虚拟机应对堆使用的最大内存数量。为此数量设置上限表示 Java 进程消耗的内存数量不得超过可用的物理内存数量。对于具有更多内存的系统可以增加此限制，96 MB 设置有助于确保 IDE 在内存量为 128MB 到 256MB 的系统上能够可靠地执行操作。注意：不要将该值设置为接近或大于系统的物理内存量，否则将在主要回收过程中导致频繁的交换操作。 </font>
		</p>
		<p>
				<font size="2">-XX:PermSize=20m - 此 JVM 开关不仅功能更为强大，而且能够缩短启动时间。该设置用于调整内存&amp;quot;永久区域&amp;quot;（类保存在该区域中）的大小。因此我们向 JVM 提示它将需要的内存量。该设置消除了许多系统启动过程中的主要垃圾收集事件。SunONE Studio 或其它包含更多模块的 IDE 的用户可能希望将该数值设置得更高。 <br />下面列出了其它一些可能对 ECLIPSE 在某些系统（不是所有系统）上的性能产生轻微或明显影响的 JVM 开关。尽管使用它们会产生一定的影响，但仍值得一试。 </font>
		</p>
		<p>
				<font size="2">-XX:CompileThreshold=100 - 此开关将降低启动速度，原因是与不使用此开关相比，HotSpot 能够更快地将更多的方法编译为本地代码。其结果是提高了 IDE 运行时的性能，这是因为更多的 UI 代码将被编译而不是被解释。该值表示方法在被编译前必须被调用的次数。 </font>
		</p>
		<p>
				<font size="2">-XX:+UseConcMarkSweepGC -XX:+UseParNewGC - 如果垃圾回收频繁中断，则请尝试使用这些开关。此开关导致 JVM 对主要垃圾回收事件（如果在多处理器工作站上运行，则也适用于次要回收事件）使用不同的算法，这些算法不会影响整个垃圾回收进程。注意：目前尚不确定此收集器是提高还是降低单处理器计算机的性能。 </font>
		</p>
		<p>
				<font size="2">-XX:+UseParallelGC - 某些测试表明，至少在内存配置相当良好的单处理器系统中，使用此回收算法可以将次要垃圾回收的持续时间减半。注意，这是一个矛盾的问题，事实上此回收器主要适用于具有千兆字节堆的多处理器。尚无可用数据表明它对主要垃圾回收的影响。注意：此回收器与 -XX:+UseConcMarkSweepGC 是互斥的。</font>
		</p>
		<p>
				<font size="2">我的机器是512MB的内存<br />下面是我的eclipse启动参数：eclipse.exe -vmargs -Xverify:none -Xms64M -Xmx256M -XX:PermSize=20M&amp;nbsp; -XX:+UseParallelGC</font>
		</p>
		<p>
				<font size="2">-----</font>
		</p>
		<p>
				<font size="2">By BeanSoft:<br />我的电脑是1G内存, 有一次内存不足了... MyEclipse 就推荐我使用一个启动参数, 现在我的启动参数是:</font>
		</p>
		<p>
				<br />
				<font size="2">eclipse.exe -vmargs -Xverify:none -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M -XX:+UseParallelGC</font>
		</p>
<img src ="http://www.blogjava.net/errorfun/aggbug/86510.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/errorfun/" target="_blank">errorfun</a> 2006-12-09 10:30 <a href="http://www.blogjava.net/errorfun/articles/86510.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]String常量之迷</title><link>http://www.blogjava.net/errorfun/articles/86511.html</link><dc:creator>errorfun</dc:creator><author>errorfun</author><pubDate>Sat, 09 Dec 2006 02:30:00 GMT</pubDate><guid>http://www.blogjava.net/errorfun/articles/86511.html</guid><wfw:comment>http://www.blogjava.net/errorfun/comments/86511.html</wfw:comment><comments>http://www.blogjava.net/errorfun/articles/86511.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/errorfun/comments/commentRss/86511.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/errorfun/services/trackbacks/86511.html</trackback:ping><description><![CDATA[
		<p>转自：<a href="http://bluebug.blog.hexun.com/5930732_d.html">http://bluebug.blog.hexun.com/5930732_d.html</a></p>
		<p>Demo:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">package</span>
				<span style="COLOR: #000000"> test;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /><br /><img id="Codehighlighter1_39_294_Open_Image" onclick="this.style.display='none'; Codehighlighter1_39_294_Open_Text.style.display='none'; Codehighlighter1_39_294_Closed_Image.style.display='inline'; Codehighlighter1_39_294_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_39_294_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_39_294_Closed_Text.style.display='none'; Codehighlighter1_39_294_Open_Image.style.display='inline'; Codehighlighter1_39_294_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> StringTest </span>
				<span id="Codehighlighter1_39_294_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_39_294_Open_Text">
						<span style="COLOR: #000000">{<br /><img id="Codehighlighter1_42_83_Open_Image" onclick="this.style.display='none'; Codehighlighter1_42_83_Open_Text.style.display='none'; Codehighlighter1_42_83_Closed_Image.style.display='inline'; Codehighlighter1_42_83_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_42_83_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_42_83_Closed_Text.style.display='none'; Codehighlighter1_42_83_Open_Image.style.display='inline'; Codehighlighter1_42_83_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_42_83_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span>
						<span id="Codehighlighter1_42_83_Open_Text">
								<span style="COLOR: #008000">/**</span>
								<span style="COLOR: #008000">
										<br />
										<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * </span>
								<span style="COLOR: #808080">@param</span>
								<span style="COLOR: #008000"> args<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * </span>
								<span style="COLOR: #808080">@author</span>
								<span style="COLOR: #008000"> dougq<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />     </span>
								<span style="COLOR: #008000">*/</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img id="Codehighlighter1_124_292_Open_Image" onclick="this.style.display='none'; Codehighlighter1_124_292_Open_Text.style.display='none'; Codehighlighter1_124_292_Closed_Image.style.display='inline'; Codehighlighter1_124_292_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
								<img id="Codehighlighter1_124_292_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_124_292_Closed_Text.style.display='none'; Codehighlighter1_124_292_Open_Image.style.display='inline'; Codehighlighter1_124_292_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </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">void</span>
						<span style="COLOR: #000000"> main(String[] args)</span>
						<span id="Codehighlighter1_124_292_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_124_292_Open_Text">
								<span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        String a </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">xyz</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        String b</span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">xyz</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        System.out.println(a</span>
								<span style="COLOR: #000000">==</span>
								<span style="COLOR: #000000">b); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        String a2 </span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">new</span>
								<span style="COLOR: #000000"> String(</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">xyz</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        String b2</span>
								<span style="COLOR: #000000">=</span>
								<span style="COLOR: #000000"> </span>
								<span style="COLOR: #0000ff">new</span>
								<span style="COLOR: #000000"> String(</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">xyz</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        System.out.println(a2</span>
								<span style="COLOR: #000000">==</span>
								<span style="COLOR: #000000">b2); <br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>Result:</p>
		<p>true<br />false<br /><br />到网上查了好些资料，最终觉得下面这篇文章是一个最为满意的答复，全文如下：<br /><br />全面理解Java中的String数据类型<br /><br />1. 首先String不属于8种基本数据类型，String是一个对象。 </p>
		<p>　　因为对象的默认值是null，所以String的默认值也是null；但它又是一种特殊的对象，有其它对象没有的一些特性。 </p>
		<p>　　2. new String()和new String(“”)都是申明一个新的空字符串，是空串不是null； </p>
		<p>　　3. String str=”kvill”； <br />String str=new String (“kvill”);的区别： </p>
		<p>　　在这里，我们不谈堆，也不谈栈，只先简单引入常量池这个简单的概念。 </p>
		<p>　　常量池(constant pool)指的是在编译期被确定，并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量，也包括字符串常量。 </p>
		<p>　　看例1： </p>
		<p>
				<br />String s0=”kvill”; <br />String s1=”kvill”; <br />String s2=”kv” + “ill”; <br />System.out.println( s0==s1 ); <br />System.out.println( s0==s2 ); </p>
		<p>
				<br />　　结果为： </p>
		<p>
				<br />true <br />true </p>
		<p>
				<br />　　首先，我们要知道Java会确保一个字符串常量只有一个拷贝。 </p>
		<p>　　因为例子中的s0和s1中的”kvill”都是字符串常量，它们在编译期就被确定了，所以s0==s1为true；而”kv”和”ill”也都是字符串常量，当一个字符串由多个字符串常量连接而成时，它自己肯定也是字符串常量，所以s2也同样在编译期就被解析为一个字符串常量，所以s2也是常量池中”kvill”的一个引用。 </p>
		<p>　　所以我们得出s0==s1==s2; </p>
		<p>　　用new String() 创建的字符串不是常量，不能在编译期就确定，所以new String() 创建的字符串不放入常量池中，它们有自己的地址空间。 </p>
		<p>　　看例2： </p>
		<p>
				<br />String s0=”kvill”; <br />String s1=new String(”kvill”); <br />String s2=”kv” + new String(“ill”); <br />System.out.println( s0==s1 ); <br />System.out.println( s0==s2 ); <br />System.out.println( s1==s2 ); </p>
		<p>
				<br />　　结果为： </p>
		<p>
				<br />false <br />false <br />false </p>
		<p>
				<br />　　例2中s0还是常量池中”kvill”的应用，s1因为无法在编译期确定，所以是运行时创建的新对象”kvill”的引用，s2因为有后半部分new String(“ill”)所以也无法在编译期确定，所以也是一个新创建对象”kvill”的应用;明白了这些也就知道为何得出此结果了。 </p>
		<p>　　4. String.intern()： </p>
		<p>　　再补充介绍一点：存在于.class文件中的常量池，在运行期被JVM装载，并且可以扩充。String的intern()方法就是扩充常量池的一个方法；当一个String实例str调用intern()方法时，Java查找常量池中是否有相同Unicode的字符串常量，如果有，则返回其的引用，如果没有，则在常量池中增加一个Unicode等于str的字符串并返回它的引用；看例3就清楚了 </p>
		<p>　　例3： </p>
		<p>
				<br />String s0= “kvill”; <br />String s1=new String(”kvill”); <br />String s2=new String(“kvill”); <br />System.out.println( s0==s1 ); <br />System.out.println( “**********” ); <br />s1.intern(); <br />s2=s2.intern(); //把常量池中“kvill”的引用赋给s2 <br />System.out.println( s0==s1); <br />System.out.println( s0==s1.intern() ); <br />System.out.println( s0==s2 ); </p>
		<p>
				<br />　　结果为： </p>
		<p>
				<br />false <br />********** <br />false //虽然执行了s1.intern(),但它的返回值没有赋给s1 <br />true //说明s1.intern()返回的是常量池中”kvill”的引用 <br />true </p>
		<p>
				<br />　　最后我再破除一个错误的理解： </p>
		<p>　　有人说，“使用String.intern()方法则可以将一个String类的保存到一个全局String表中，如果具有相同值的Unicode字符串已经在这个表中，那么该方法返回表中已有字符串的地址，如果在表中没有相同值的字符串，则将自己的地址注册到表中“如果我把他说的这个全局的String表理解为常量池的话，他的最后一句话，“如果在表中没有相同值的字符串，则将自己的地址注册到表中”是错的： </p>
		<p>　　看例4： </p>
		<p>
				<br />String s1=new String(&amp;quot;kvill&amp;quot;); <br />String s2=s1.intern(); <br />System.out.println( s1==s1.intern() ); <br />System.out.println( s1+&amp;quot; &amp;quot;+s2 ); <br />System.out.println( s2==s1.intern() ); </p>
		<p>
				<br />　　结果： </p>
		<p>
				<br />false <br />kvill kvill <br />true </p>
		<p>
				<br />　　在这个类中我们没有声名一个”kvill”常量，所以常量池中一开始是没有”kvill”的，当我们调用s1.intern()后就在常量池中新添加了一个”kvill”常量，原来的不在常量池中的”kvill”仍然存在，也就不是“将自己的地址注册到常量池中”了。 </p>
		<p>　　s1==s1.intern()为false说明原来的“kvill”仍然存在； </p>
		<p>　　s2现在为常量池中“kvill”的地址，所以有s2==s1.intern()为true。 </p>
		<p>　　5. 关于equals()和==: </p>
		<p>　　这个对于String简单来说就是比较两字符串的Unicode序列是否相当，如果相等返回true;而==是比较两字符串的地址是否相同，也就是是否是同一个字符串的引用。 </p>
		<p>　　6. 关于String是不可变的</p>
		<p>　　这一说又要说很多，大家只要知道String的实例一旦生成就不会再改变了，比如说：String str=”kv”+”ill”+” “+”ans”; <br />就是有4个字符串常量，首先”kv”和”ill”生成了”kvill”存在内存中，然后”kvill”又和” “ 生成 ”kvill “存在内存中，最后又和生成了”kvill ans”;并把这个字符串的地址赋给了str,就是因为String的“不可变”产生了很多临时变量，这也就是为什么建议用StringBuffer的原因了，因为StringBuffer是可改变的。</p>
<img src ="http://www.blogjava.net/errorfun/aggbug/86511.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/errorfun/" target="_blank">errorfun</a> 2006-12-09 10:30 <a href="http://www.blogjava.net/errorfun/articles/86511.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>