??xml version="1.0" encoding="utf-8" standalone="yes"?>精品亚洲国产成AV人片传媒,亚洲影院在线观看,亚洲一区二区电影http://www.tkk7.com/errorfun/category/18234.htmlM事情只要开始去做,永远不会太迟?/description>zh-cnTue, 27 Feb 2007 12:31:29 GMTTue, 27 Feb 2007 12:31:29 GMT60[转]Java应用E序本地~译为EXE的几U方?/title><link>http://www.tkk7.com/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.tkk7.com/errorfun/articles/86567.html</guid><wfw:comment>http://www.tkk7.com/errorfun/comments/86567.html</wfw:comment><comments>http://www.tkk7.com/errorfun/articles/86567.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/errorfun/comments/commentRss/86567.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/errorfun/services/trackbacks/86567.html</trackback:ping><description><![CDATA[ <p> <font size="2">Java应用E序本地~译为EXE的几U方?推荐使用JOVE和JET)  <br />1. 从www.towerj.com获得一个TowerJ~译器,该编译器可以你的CLASS文g  <br />~译成EXE文g。 <br /> <br />2. 利用微Y的SDK-Java 4.0所提供的jexegen.exe创徏EXE文gQ这个Y件可以  <br />从微软的|站免费下蝲Q地址如下Q  <br /></font> <a > <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文g的本地编译器。你需要安装该光盘  <br />上提供的EXElg。 <br /> <br />4. 使用InstallAnywhere创徏安装盘。 <br /> <br />5. 使用IBM AlphaWorks提供的一个高性能Java~译器,该编译器可以从下面的  <br />地址获得Q  <br /></font> <a > <font size="2">http://www.alphaworks.ibm.com/tech/hpc</font> </a> <font size="2">  <br /><br />6. JET是一个优U的Java语言本地~译器。该~译器可以从q个|站获得一个  <br />试版本Q  <br /></font> <a > <font size="2">http://www.excelsior-usa.com/jet.html</font> </a> <font size="2">  <br /><br />7. Instantiations公司的JOVE  <br /></font> <a > <font size="2">http://www.instantiations.com/jove/...ejovesystem.htm</font> </a> <font size="2">  <br />JOVE公司合ƈ了以前的SuperCedeQ一个优U的本地编译器Q现在SuperCede  <br />已经不复存在了。  <br /><br />8. JToEXE  <br />Bravo Zulu Consulting, Inc开发的一ƾ本地编译器Q本来可以从该公司的  <br />|页上免费下载的Q不q目前在该公司的主页上找不到了。?/font> </p> <img src ="http://www.tkk7.com/errorfun/aggbug/86567.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/errorfun/" target="_blank">errorfun</a> 2006-12-09 18:33 <a href="http://www.tkk7.com/errorfun/articles/86567.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]提高java代码的性能http://www.tkk7.com/errorfun/articles/86566.htmlerrorfunerrorfunSat, 09 Dec 2006 10:31:00 GMThttp://www.tkk7.com/errorfun/articles/86566.htmlhttp://www.tkk7.com/errorfun/comments/86566.htmlhttp://www.tkk7.com/errorfun/articles/86566.html#Feedback0http://www.tkk7.com/errorfun/comments/commentRss/86566.htmlhttp://www.tkk7.com/errorfun/services/trackbacks/86566.html N归及其转换 
相当多的E序包含有@环,q些循环q行的时间占了程序总运行时间的很大一部分。这些@环经常要反复更新不止一个变量,而每个变量的更新又经怾赖于其它变量的倹{?br />
如果把P代看成是N归函数Q那么,可以把q些变量看成是函数的参数。简单提醒一下:如果一个调用的q回D作ؓ调用函数的值立卌回,那么Q这个递归调用是N归Q尾递归不必C调用时调用函数的上下文。?br />
׃q一特点Q在N归函数和@环之间有一个很好的对应关系Q可以简单地把每个递归调用看作是一个@环的多次q代。但因ؓ所有可变的参数值都一ơ传l了递归调用Q所以比起@环来Q在N归中可以更Ҏ地得到更新倹{而且Q难以用的 break 语句也常ؓ函数的简单返回所替代。 ?br />
但在 Java ~程中,用这U方式表CP代将D效率低下Q因为大量的递归调用有导致堆栈溢出的危险。 ?br />
解决Ҏ比较单:因ؓN归函数实际上只是编写@环的一U更单的方式Q所以就让编译器把它们自动{换成循环形式。这h同时利用了q两UŞ式的优点。 ?br />
但是Q尽大安熟知如何把一个尾递归函数自动转换成一个简单@环,Java 规范却不要求做这U{换。不作这U要求的原因大概是:通常在面向对象的语言中,q种转换不能静态地q行。相反地Q这U从N归函数到简单@环的转换必须由 JIT ~译器动态地q行。 ?br />
要理解ؓ什么会是这P考虑下面一个失败的试Q在 Integers 集上Q把 Iterator 中的元素怹。 ?br />
因ؓ下面的程序中有一个错误,所以在q行时会抛出一个异常。但是,p在本专栏以前的许多文章中已经的那P一个程序抛出的_异常Q跟很棒的错误类型标识符一P对于扑ֈ错误藏在E序的什么地方ƈ没有什么帮助,我们也不想编译器以这U方式改变程序,以ɾ~译的结果代码抛Z个不同的异常。 ?br />
[清单 1. 一个把 Integer 集的 Iterator 中的元素怹的失败尝试 ]

import  java.util.Iterator; 

public   class  Example 

  
public   int  product(Iterator i) 
    
return  productHelp(i,  0 ); 
  }
 

  
int  productHelp(Iterator i,  int  accumulator) 
    
if  (i.hasNext()) 
      
return  productHelp(i, accumulator  *  ((Integer)i.next()).intValue()); 
    }
 
    
else  
      
return  accumulator; 
    }
 
  }
 
}
 


注意 product Ҏ中的错误。product Ҏ通过把 accumulator 赋gؓ 0 调用 productHelp。它的值应为?。否则,在类 Example 的Q何实例上调用 product 都将产生 0 |不管 Iterator 是什么倹{ ?br />
假设q个错误l于被改正了Q但同时Q类 Example 的一个子cM被创ZQ如清单 2 所C: 

[清单 2. 试图捕捉象清单? q样的不正确的调用] 

import  java.util. *

class  Example 

  
public   int  product(Iterator i) 
    
return  productHelp(i,  1 ); 
  }
 

  
int  productHelp(Iterator i,  int  accumulator) 
    
if  (i.hasNext()) 
      
return  productHelp(i, accumulator  *  ((Integer)i.next()).intValue()); 
    }
 
    
else  
      
return  accumulator; 
    }
 
  }
 
}
 

 


//  And, in a separate file: 

import  java.util. *

public   class  Example2  extends  Example 
  
int  productHelp(Iterator i,  int  accumulator) 
    
if  (accumulator  <   1
      
throw   new  RuntimeException( " accumulator to productHelp must be >= 1 " ); 
    }
 
    
else  
      
return   super .productHelp(i, accumulator); 
    }
 
  }
 

  
public   static   void  main(String[] args) 
    LinkedList l 
=   new  LinkedList(); 
    l.add(
new  Integer( 0 )); 
    
new  Example2().product(l.listIterator()); 
  }
 
}

c Example2 中的被覆盖的 productHelp Ҏ试图通过当 accumulator 于?”时抛出q行时异常来捕捉对 productHelp 的不正确调用。不q的是,q样做将引入一个新的错误。如果 Iterator 含有M 0 值的实例Q都 productHelp 在自w的递归调用上崩溃。 ?br />
现在h意,在类 Example2 的 main Ҏ中,创徏了 Example2 的一个实例ƈ调用了它的 product Ҏ。由于传l这个方法的 Iterator 包含一个?Q因此程序将崩溃。 ?br />
然而,您可以看到类 Example 的 productHelp 是严格尾递归的。假设一个静态编译器xq个Ҏ的正文{换成一个@环,如清单? 所C:  

[清单 3. 静态编译不会优化尾调用的一个示例]  

int  productHelp(Iterator i,  int  accumulator) 
    
while  (i.hasNext()) 
      accumulator 
*=  ((Integer)i.next()).intValue(); 
    }
 
    
return  accumulator; 
  }
 



于是Q最初对 productHelp 的调用,l果成了对超cȝҎ的调用。超Ҏ通过单地在 iterator 上@环来计算其结果。不会抛ZQ何异常。 ?br />
用两个不同的静态编译器来编译这D代码,l果是一个会抛出异常Q而另一个则不会Q想惌是多么让人感到困惑。 ?br />
您的 JIT 会做q种转换吗?
因此Q如清单 3 中的CZ所C,我们不能期望静态编译器会在保持语言语义的同时对 Java 代码执行N归转换。相反地Q我们必M靠 JIT q行的动态编译。JIT 会不会做q种转换是取决于 JVM。 ?br />
要判断您的 JIT 会否转换N归的一个办法是~译q运行如下小试c:  

[清单 4. 判断您的 JIT 能否转换N归]

public   class  TailRecursionTest 

  
private   static   int  loop( int  i) 
    
return  loop(i); 
  }
 

  
public   static   void  main(String[] args) 
    loop(
0 ); 
  }
 
}
 



我们来考虑一下这个类的 loop Ҏ。这个方法只是尽可能长时间地对自w作递归调用。因为它永远不会q回Q也不会以Q何方式媄响Q何外部变量,因此如清单? 所C替换其代码正文保留程序的语义。 ?br />
[清单 5. 一个动态{换]

public   class  TailRecursionTest 

  
private   static   int  loop( int  i) 
    
while  ( true
    }
 
  }
 

  
public   static   void  main(String[] args) 
    loop(
0 ); 
  }
 
}
 


  
而且Q事实上q也是_完善的编译器所做的转换。 ?br />
如果您的 JIT ~译器把N归调用转换成P代,q个E序无限期地运行下厅R它所需的内存很,而且不会随时间增加。 ?br />
另一斚wQ如果 JIT 不做q种转换Q程序将会很快耗尽堆栈I间q报告一个堆栈溢出错误。 ?br />
我在两个 Java SDK 上运行这个程序,l果令h惊讶。在 SUN 公司的 Hotspot JVMQ版本?.3 Q上q行Ӟ发现 Hotspot 不执行这U{换。缺省设|下Q在我的机器上运行时Q不CU钟堆栈I间p耗尽了。 ?br />
另一斚wQ程序在 IBM 的 JVMQ版本?.3 Q上咕噜噜运行时却没有Q何问题,q表明 IBM 的 JVM 以这U方式{换代码。 ?br />
ȝ
CQ我们不能寄希望于我们的代码会Lq行在会转换N归调用的 JVM 上。因此,Z保证您的E序在所有 JVM 上都有适当的性能Q您应始l努力把那些最自然地符合尾递归模式的代码按q代风格~写。 ?br />
但是h意:p我们的示例所演示的那P以这U方式{换代码时很容易引入错误,不论是由人工q是pY件来完成q种转换?/font>

文章摘自Q?/font> http://www-900.ibm.com/
作者:Eric Allen



errorfun 2006-12-09 18:31 发表评论
]]>
[转]JavaU程的缺?/title><link>http://www.tkk7.com/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.tkk7.com/errorfun/articles/86532.html</guid><wfw:comment>http://www.tkk7.com/errorfun/comments/86532.html</wfw:comment><comments>http://www.tkk7.com/errorfun/articles/86532.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/errorfun/comments/commentRss/86532.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/errorfun/services/trackbacks/86532.html</trackback:ping><description><![CDATA[ <font size="2">Java 语言的线E模型是此语a的一个最隑֏人满意的部分。尽 Java 语言本n支持线E编E是件好事,但是它对U程的语法和cd的支持太,只能适用于极型的应用环境?br /><br />关于 Java U程~程的大多数书籍都长篏牍地指出了 Java U程模型的缺Pq提供了解决q些问题的急救?Band-Aid/邦_创可?cd。我U这些类为急救包,是因为它们所能解决的问题本应是由 Java 语言本n语法所包含的。从长远来看Q以语法而不是类库方法,能产生更高效的代码。这是因为编译器和 Java 虚拟器?JVM) 能一同优化程序代码,而这些优化对于类库中的代码是很难或无法实现的?br /><br />在我的《Taming Java Threads 》(请参阅 参考资料 )书中以及本文中,我进一步徏议对 Java ~程语言本nq行一些修改,以得它能够真正解决q些U程~程的问题。本文和我这本书的主要区别是Q我在撰写本文时q行了更多的思? 所以对书中的提议加以了提高。这些徏议只是尝试性的 -- 只是我个人对q些问题的想法,而且实现q些x需要进行大量的工作以及同行们的评h。但q是毕竟是一个开端,我有意ؓ解决q些问题成立一个专门的工作l,如果您感兴趣Q请发 e-mail 刊W?/font> <a href="mailto:threading@holub.com" target="_blank"> <font size="2">threading@holub.com</font> </a> <font size="2"> 。一旦我真正着手进行,我就会给您发通知?br /><br />q里提出的徏议是非常大胆的。有些h对 Java 语言规范 (JLS)Q请参阅参考资料 )q行l微和少量的修改以解军_前模p的 JVM 行ؓQ但是我却想对其q行更ؓd的改q?br /><br />在实际草E中Q我的许多徏议包括ؓ此语a引入新的关键字。虽焉常要求不要H破一个语a的现有代码是正确的,但是如果该语a的ƈ不是要保持不变以至于q时的话Q它必能引入新的关键字。ؓ了引入的关键字与现有的标识W不产生冲突Q经q细心考虑Q我用一个?$) 字符Q而这个字W在现有的标识符中是非法的?例如Q用?taskQ而不是 task)。此旉要编译器的命令行开x供支持,能用这些关键字的变体,而不是忽略这个美元符受?/font> <p> <font size="2"> <strong>taskQQ务)的概?br /><br /></strong>Java U程模型的根本问题是它完全不是面向对象的。面向对象?OO) 设计人员Ҏ不按U程角度考虑问题Q他们考虑的是同步 信息 异步 信息Q同步信息被立即处理 -- 直到信息处理完成才返回消息句柄;异步信息收到后将在后台处理一D|闾b?- 而早在信息处理结束前p回消息句柄)。Java ~程语言中的 Toolkit.getImage() Ҏ是异步信息的一个好例子。 getImage() 的消息句柄将被立卌回,而不必等到整个图像被后台U程取回?br /><br />q是面向对象 (OO) 的处理方法。但是,如前所qͼJava 的线E模型是非面向对象的。一个 Java ~程语言U程实际上只是一个run() q程Q它调用了其它的q程。在q里根本没有对象、异步或同步信息以及其它概念?br /><br />对于此问题,在我的书中深入讨的一个解x法是Q用一个Active_object。 active 对象是可以接收异步请求的对象Q它在接收到h后的一D|间内以后台方式得以处理。在 Java ~程语言中,一个请求可被封装在一个对象中。例如,你可以把一个通过 Runnable 接口实现的实例传送给此 active 对象Q该接口的 run() Ҏ装了需要完成的工作。该 runnable 对象被此 active 对象排入到队列中Q当轮到它执行时Qactive 对象使用一个后台线E来执行它?br /><br />在一个 active 对象上运行的异步信息实际上是同步的,因ؓ它们被一个单一的服务线E按序从队列中取出q执行。因此,使用一个 active 对象以一U更E化的模型可以消除大多数的同步问题?br /><br />在某U意义上QJava ~程语言的整个 Swing/AWT 子系l是一个 active 对象。向一个 Swing 队列传送一条讯息的唯一安全的途径是,调用一个类似SwingUtilities.invokeLater() 的方法,q样在 Swing 事g队列上发送了一个 runnable 对象Q当轮到它执行时Q Swing 事g处理U程会处理它?br /><br />那么我的W一个徏议是Q向 Java ~程语言中加入一个task QQ务)的概念,从而将active 对象集成到语a中? task的概忉|从 Intel 的 RMX 操作pȝ和 Ada ~程语言借鉴q来的。大多数实时操作pȝ都支持类似的概念。)<br /><br />一个Q务有一个内|的 active 对象分发E序Qƈ自动理那些处理异步信息的全部机制?br /><br />定义一个Q务和定义一个类基本相同Q不同的只是需要在d的方法前加一个asynchronous 修饰W来指示 active 对象的分配程序在后台处理q些Ҏ。请参考我的书中第九章的基于类ҎQ再看以下的 file_io c,它用了在《 Taming Java Threads 》中所讨论的 Active_object cL实现异步写操作:<br /><br />所有的写请求都用一个dispatch() q程调用被放在 active-object 的输入队列中排队。在后台处理q些异步信息时出现的M异常 (exception) 都由 Exception_handler 对象处理Q此 Exception_handler 对象被传送到 File_io_task 的构造函C。您要写内容到文件时Q代码如下:<br /><br />q种Zcȝ处理ҎQ其主要问题是太复杂了?- 对于一个这L单的操作Q代码太杂了。向 Java 语言引入$task 和?asynchronous 关键字后Q就可以按下面这样重写以前的代码Q?br /><br />注意Q异步方法ƈ没有指定q回|因ؓ其句柄将被立卌回,而不用等到请求的操作处理完成后。所以,此时没有合理的返回倹{对于派生出的模型,$task 关键字和 class 一样同效: $task 可以实现接口、承类和承的其它d。标有 asynchronous 关键字的Ҏ由?task 在后台处理。其它的Ҏ同步运行,像在类中一栗?br /><br />$task关键字可以用一个可选的 $error 从句修饰 (如上所C?Q它表明对Q何无法被异步Ҏ本n捕捉的异常将有一个缺省的处理E序。我使用 $ 来代表被抛出的异常对象。如果没有指定?error 从句Q就打印出一个合理的出错信息Q很可能是堆栈跟t信息)?br /><br />注意Qؓ保U程安全Q异步方法的参数必须是不变?immutable) 的。运行时pȝ应通过相关语义来保证这U不变性(单的复制通常是不够的Q?br /><br />所有的 task 对象必须支持一些伪信息 (pseudo-message)Q例如:<br /><br />除了常用的修饰符Qpublic {?Q task 关键字还应接受一个?pooled(n) 修饰W,它导臾btask 使用一个线E池Q而不是用单个线E来q行异步h。 n 指定了所需U程池的大小Q必要时Q此U程池可以增加,但是当不再需要线E时Q它应该~到原来的大。伪域?pseudo-field) $pool_size q回在?pooled(n) 中指定的原始 n 参数倹{?br /><br />在《Taming Java Threads 》的W八章中Q我l出了一个服务器端的 socket 处理E序Q作为线E池的例子。它是关于用线E池的Q务的一个好例子。其基本思\是生一个独立对象,它的d是监控一个服务器端的 socket。每当一个客hq接到服务器Ӟ服务器端的对象会从池中抓取一个预先创建的睡眠U程Qƈ把此U程讄为服务于客户端连接。socket 服务器会产出一个额外的客户服务U程Q但是当q接关闭Ӟq些额外的线E将被删除。实玊Wsocket 服务器的推荐语法如下Q?br /><br />Socket_server对象使用一个独立的后台U程处理异步的 listen() hQ它装 socket ?接受"循环。当每个客户端连接时Q listen() h一个 Client_handler 通过调用 handle() 来处理请求。每个 handle() h在它们自qU程中执行(因ؓq是一个?pooled d)?br /><br />注意Q每个传送到$pooled $task 的异步消息实际上都用它们自qU程来处理。典型情况下Q由于一个?pooled $task 用于实现一个自L作;所以对于解决与讉K状态变量有关的潜在的同步问题,最好的解决Ҏ是在 $asynchronous Ҏ中用 this 是指向的对象的一个独有副本。这是_当向一个?pooled $task 发送一个异步请求时Q将执行一个 clone() 操作Qƈ且此Ҏ的 this 指针会指向此克隆对象。线E之间的通信可通过对 static 区的同步讉K实现?/font> </p> <br /> <p> <font size="2"> <strong>改进synchronized<br /></strong> <br />虽然在多数情况下Q?task 消除了同步操作的要求Q但是不是所有的多线E系l都用Q务来实现。所以,q需要改q现有的U程模块。 synchronized 关键字有下列~点Q 无法指定一个超时倹{ 无法中断一个正在等待请求锁的线E。 无法安全地h多个锁 ?多个锁只能以依次序获得?<br /><br />解决q些问题的办法是Q扩展synchronized 的语法,使它支持多个参数和能接受一个超时说明(在下面的括弧中指定)。下面是我希望的语法Q?br /><br />synchronized(x && y && z) 获得 x、y 和 z 对象的锁。?br />synchronized(x || y || z) 获得 x、y 或 z 对象的锁。?br />synchronized( (x && y ) || z) 对于前面代码的一些扩展。?br />synchronized(...)[1000] 讄 1 U超时以获得一个锁。?br />synchronized[1000] f(){...} 在进入 f() 函数时获得 this 的锁Q但可有 1 U超时。?br /><br />TimeoutException是 RuntimeException zc,它在{待时后即被抛出?br /><br />时是需要的Q但q不以使代码强壮。您q需要具备从外部中止h锁等待的能力。所以,当向一个等待锁的线E传送一个interrupt() Ҏ后,此方法应抛出一个 SynchronizationException 对象Qƈ中断{待的线E。这个异常应是 RuntimeException 的一个派生类Q这样不必特别处理它?br /><br />对synchronized 语法q些推荐的更Ҏ法的主要问题是,它们需要在二进制代码上修攏V而目前这些代码用进入监?enter-monitor)和退出监?exit-monitor)指o来实玊Wsynchronized 。而这些指令没有参敎ͼ所以需要扩展二q制代码的定义以支持多个锁定h。但是这U修改不会比在 Java 2 中修改 Java 虚拟机的更轻松,但它是向下兼容现存的 Java 代码?br /><br />另一个可解决的问题是最常见的死锁情况,在这U情况下Q两个线E都在等待对方完成某个操作。设想下面的一个例子(假设的)Q?br /><br />设想一个线E调用a() Q但在获得  lock1 之后在获得 lock2 之前被剥行权。 第二个U程q入q行Q调用 b() Q获得了 lock2 Q但是由于第一个线E占用 lock1 Q所以它无法获得 lock1 Q所以它随后处于{待状态。此时第一个线E被唤醒Q它试图获得 lock2 Q但是由于被W二个线E占据,所以无法获得。此时出现死锁。下面的 synchronize-on-multiple-objects 的语法可解决q个问题Q?br /><br />~译?或虚拟机)会重新排列请求锁的顺序,使lock1 L被首先获得,q就消除了死锁?br /><br />但是Q这U方法对多线E不一定L功,所以得提供一些方法来自动打破死锁。一个简单的办法是在等待第二个锁时帔R攑ַ获得的锁。这是_应采取如下的{待方式Q而不是永q等待:<br /><br />如果{待锁的每个E序使用不同的超时|可打破死锁而其中一个线E就可运行。我用以下的语法来取代前面的代码Q?br /><br />synchronized语句永q等待,但是它时怼攑ּ已获得的锁以打破潜在的死锁可能。在理想情况下,每个重复{待的超时值比前一个相差一随机倹{?br /><br /><strong>改进wait() 和 notify()</strong><br /><br />wait()/ notify() pȝ也有一些问题: 无法 wait() 是正常返回还是因时q回。 无法用传l条件变量来实现处于一?信号"(signaled)状态。 太Ҏ发生嵌套的监?monitor)锁定?br /><br />时问题可以通过重新定义wait() 使它q回一个 boolean 变量 (而不是 void ) 来解冟뀂一个 true q回值指CZ个正常返回,而 false 指示因超时返回?br /><br />Z状态的条g变量的概忉|很重要的。如果此变量被设|成false 状态,那么{待的线E将要被LQ直到此变量q入 true 状态;M{待 true 的条件变量的{待U程会被自动释放。?在这U情况下Q wait() 调用不会发生L?。通过如下扩展 notify() 的语法,可以支持q个功能Q?br /><br />嵌套监控锁定问题非常ȝQ我q没有简单的解决办法。嵌套监控锁定是一U死锁Ş式,当某个锁的占有线E在挂v其自w之前不释放锁时Q会发生q种嵌套监控锁。下面是此问题的一个例子(q是假设的)Q但是实际的例子是非常多的:<br /><br />此例中,在get() 和 put() 操作中涉及两个锁Q一个在 Stack 对象上,另一个在 LinkedList 对象上。下面我们考虑当一个线E试图调用一个空栈的 pop() 操作时的情况。此U程获得q两个锁Q然后调用 wait() 释放 Stack 对象上 的锁,但是没有释放在 list 上的锁。如果此时第二个U程试图向堆栈中压入一个对象,它会在 synchronized(list) 语句上永q挂P而且永远不会被允许压入一个对象。由于第一个线E等待的是一个非I栈Q这样就会发生死锁。这是_W一个线E永q无法从 wait() q回Q因为由于它占据着锁,而导致第二个U程永远无法q行刊Wnotify() 语句?br /><br />在这个例子中Q有很多明显的办法来解决问题Q例如,对Q何的Ҏ都用同步。但是在真实世界中,解决Ҏ通常不是q么单?br /><br />一个可行的Ҏ是,在wait() 中按照反序释放当前U程获取的 所有 锁Q然后当{待条g满后,重新按原始获取顺序取得它们。但是,我能惌出利用这U方式的代码对于Z来说直无法理解,所以我认ؓ它不是一个真正可行的Ҏ。如果您有好的方法,L我发 e-mail?br /><br />我也希望能等Cq复杂条件被实现的一天。例如:<br /><br />其中a 、 b 和 c 是Q意对象?br /><br /></font> <font size="2"> <strong>修改Thread c?br /></strong> <br />同时支持抢占式和协作式线E的能力在某些服务器应用E序中是基本要求Q尤其是在想使系l达到最高性能的情况下。我认ؓ Java ~程语言在简化线E模型上走得太远了,q且 Java ~程语言应支持 Posix/Solaris ?l色(green)U程"?M(lightweight)q程"概念Q在"QTaming Java Threads "W一章中讨论Q。 这是_有些 Java 虚拟机的实现Q例如在 NT 上的 Java 虚拟机)应在其内部仿真协作式q程Q其它 Java 虚拟机应仿真抢占式线E。而且向 Java 虚拟机加入这些扩展是很容易的?br /><br />一个 Java 的Thread 应始l是抢占式的。这是_一个 Java ~程语言的线E应像 Solaris 的轻便进E一样工作。 Runnable 接口可以用于定义一个 Solaris 式的"l色U程"Q此U程必需能把控制权{l运行在相同Mq程中的其它l色U程?br /><br />例如Q目前的语法Q?br /><br />能有效地为Runnable 对象产生一个绿色线E,q把它绑定到由 Thread 对象代表的轻便进E中。这U实现对于现有代码是透明的,因ؓ它的有效性和现有的完全一栗?br /><br />把Runnable 对象x为绿色线E,使用q种ҎQ只需向 Thread 的构造函C递几个 Runnable 对象Q就可以扩展 Java ~程语言的现有语法,以支持在一个单一MU程有多个绿色线E。(l色U程之间可以怺协作Q但是它们可被运行在其它Mq程 ( Thread 对象) 上的l色q程( Runnable 对象) 抢占。)。例如,下面的代码会为每个 runnable 对象创徏一个绿色线E,q些l色U程会共享由 Thread 对象代表的轻便进E?br /><br />现有的覆?override)Thread 对象q实玊Wrun() 的习惯l有效,但是它应映射C个被l定CMq程的绿色线E?在 Thread() cM的缺省 run() Ҏ会在内部有效地创建第二个 Runnable 对象?<br /><br /></font> <font size="2"> <strong>U程间的协作<br /></strong> <br />应在语言中加入更多的功能以支持线E间的相互通信。目前,PipedInputStream 和 PipedOutputStream cd用于q个目的。但是对于大多数应用E序Q它们太׃。我向 Thread cd入下列函敎ͼ 增加一个 wait_for_start() ҎQ它通常处于d状态,直到一个线E的 run() Ҏ启动?如果{待的线E在调用 run 之前被释放,q没有什么问题)。用q种ҎQ一个线E可以创Z个或多个辅助U程Qƈ保证在创建线El执行操作之前,q些辅助U程会处于运行状态。 (向 Object c)增加 $send (Object o) 和 Object=$receive() ҎQ它们将使用一个内部阻断队列在U程之间传送对象。阻断队列应作ؓW一个?send() 调用的副产品被自动创建。?send() 调用会把对象加入队列。?receive() 调用通常处于d状态,直到有一个对象被加入队列Q然后它q回此对象。这U方法中的变量应支持讑֮入队和出队的操作时能力Q?send (Object o, long timeout) 和?receive (long timeout)?br /><br /></font> <font size="2"> <strong>对于d锁的内部支持<br /></strong> <br />d锁的概念应内|到 Java ~程语言中。读写器锁在"Taming Java Threads "Q和其它地方Q中有详l讨论,概括地说Q一个读写锁支持多个U程同时讉K一个对象,但是在同一时刻只有一个线E可以修Ҏ对象Qƈ且在讉Kq行时不能修攏V读写锁的语法可以借用 synchronized 关键字:<br /><br />对于一个对象,应该只有?writing 块中没有U程Ӟ才支持多个线E进入?reading 块。在q行L作时Q一个试图进入?writing 块的U程会被LQ直到读U程退出?reading 块。 当有其它线E处于?writing 块时Q试图进入?reading 或?writing 块的U程会被LQ直到此写线E退出?writing 块?br /><br />如果d写线E都在等待,~省情况下,ȝE会首先q行。但是,可以使用$writer_priority 属性修改类的定义来改变q种~省方式。如Q?br />讉K部分创徏的对象应是非法的<br /><br />当前情况下,JLS 允许讉K部分创徏的对象。例如,在一个构造函C创徏的线E可以访问正被创建的对象Q既使此对象没有完全被创建。下面代码的l果无法定Q?br /><br />讄x 为?1 的线E可以和讄 x 为? 的线E同时进行。所以,此时 x 的值无法预?br /><br />Ҏ问题的一个解x法是Q在构造函数没有返回之前,对于在此构造函C创徏的线E,既它的优先U比调用new 的线E高Q也要禁止运行它的 run() Ҏ?br /><br />q就是说Q在构造函数返回之前,start() h必须被推q?br /><br />另外QJava ~程语言应可允许构造函数的同步。换句话_下面的代码(在当前情况下是非法的Q会象预期的那样工作Q?br /><br />我认为第一U方法比W二U更z,但实现v来更为困难?br /><br />volatile关键字应象预期的那样工作<br /><br />JLS 要求保留对于 volatile 操作的请求。大多数 Java 虚拟机都单地忽略了这部分内容Q这是不应该的。在多处理器的情况下Q许多主机都出现了这U问题,但是它本应由 JLS 加以解决的。如果您对这斚w感兴,马里兰大学的 Bill Pugh 正在致力于这工作(请参阅参考资料 )?br /><br /></font> <font size="2"> <strong>讉K的问?br /></strong> <br />如果~少良好的访问控Ӟ会ɾU程~程非常困难。大多数情况下,如果能保证线E只从同步子pȝ中调用,不必考虑U程安全(threadsafe)问题。我对 Java ~程语言的访问权限概念做如下限制Q应_使用 package 关键字来限制包访问权。我认ؓ当缺省行为的存在是Q何一U计机语言的一个瑕疵,我对现在存在q种~省权限感到很迷惑(而且q种~省??package)"U别的而不?U有(private)"Q。在其它斚wQJava ~程语言都不提供{同的缺省关键字。虽然用显式的 package 的限定词会破坏现有代码,但是它将使代码的可读性更强,q能消除整个cȝ潜在错误 (例如Q如果访问权是由于错误被忽略Q而不是被故意忽略)。 重新引入 private protected Q它的功能应和现在的 protected 一P但是不应允许包别的讉K。 允许 private private 语法指定"实现的访?对于所有外部对象是U有的,甚至是当前对象是的同一个类的。对?."左边的唯一引用Q隐式或昑ּQ应是 this 。 扩展 public 的语法,以授权它可制定特定类的访问。例如,下面的代码应允许 Fred cȝ对象可调用 some_method() Q但是对其它cȝ对象Q这个方法应是私有的?br /><br />q种不同于 C++ 的?friend" 机制。 在 "friend" 机制中,它授权一个类讉K另一个类的所有 私有部分。在q里Q我Ҏ限的Ҏ集合q行严格控制的访问。用q种ҎQ一个类可以为另一个类定义一个接口,而这个接口对pȝ的其余类是不可见的。一个明昄变化是:<br /><br />除非域引用的是真正不?immutable)的对象或static final 基本cdQ否则所有域的定义应是 private 。对于一个类中域的直接访问违反了 OO 设计的两个基本规则:抽象和封装。从U程的观Ҏ看,允许直接讉K域只使对它进行非同步讉K更容易一些?br /><br />增加$property 关键字。带有此关键字的对象可被一?bean ?应用E序讉KQ这个程序用在 Class cM定义的反操?introspection) APIQ否则与 private private 同效。?property 属性可用在域和ҎQ这L有的 JavaBean getter/setter Ҏ可以很容易地被定义ؓ属性?br /><br /><strong>不变?immutability)</strong><br /><br />׃对不变对象的讉K不需要同步,所以在多线E条件下Q不变的概念Q一个对象的值在创徏后不可更改)是无L。Java ~程a语中Q对于不变性的实现不够严格Q有两个原因Q对于一个不变对象,在其被未完全创徏之前Q可以对它进行访问。这U访问对于某些域可以产生不正的倹{ 对于恒定?cȝ所有域都是 final) 的定义太松散。对于由 final 引用指定的对象,虽然引用本n不能改变Q但是对象本w可以改变状态?br /><br />W一个问题可以解冻I不允许线E在构造函C开始执行?或者在构造函数返回之前不能执行开始请??br /><br />对于W二个问题,通过限定final 修饰W指向恒定对象,可以解决此问题。这是_对于一个对象,只有所有的域是 finalQƈ且所有引用的对象的域也都是 finalQ此对象才真正是恒定的。ؓ了不打破现有代码Q这个定义可以用编译器加强Q即只有一个类被显式标Z变时Q此cL是不变类。方法如下:<br /><br />有了$immutable 修饰W后Q在域定义中的 final 修饰W是可选的?br /><br />最后,当用内部类(inner class)后,在 Java ~译器中的一个错误它无法可靠地创徏不变对象。当一个类有重要的内部cL(我的代码常有)Q编译器l常不正地昄下列错误信息Q?br /><br />既ɽI的 final 在每个构造函C都有初始化,q是会出现这个错误信息。自从在 1.1 版本中引入内部类后,~译器中一直有q个错误。在此版本中Q三q以后)Q这个错误依然存在。现在,该是Ҏq个错误的时候了?br /><br /></font> <font size="2"> <strong>对于cȝ域的实例U访?br /></strong> <br />除了讉K权限外,q有一个问题,即类U(静态)Ҏ和实例(非静态)Ҏ都能直接讉KcȝQ静态)域。这U访问是非常危险的,因ؓ实例Ҏ的同步不会获取类U的锁,所以一个synchronized static Ҏ和一个 synchronized Ҏq是能同时访问类的域。改正此问题的一个明昄Ҏ是,要求在实例方法中只有使用 static 讉KҎ才能讉K非不变类的 static 域。当Ӟq种要求需要编译器和运行时间检查。在q种规定下,下面的代码是非法的:<br /><br />׃f() 和 g() 可以q行q行Q所以它们能同时改变 x 的|产生不定的结果)。请CQ这里有两个锁: static Ҏ要求属于 Class 对象的锁Q而非静态方法要求属于此cd例的锁。当从实例方法中讉K非不变 static 域时Q编译器应要求满下面两个结构中的Q意一个:<br /><br />或则Q编译器应获得读/写锁的用:<br /><br />另外一U方法是Q这也是一U理想的 ҎQ?- ~译器应 自动 使用一个读/写锁来同步访问非不变 static 域,q样Q程序员׃必担心这个问题?br /><br /><strong>后台U程的突然结?/strong><br /><br />当所有的非后台线E终止后Q后台线E都被突然结束。当后台U程创徏了一些全局资源Q例如一个数据库q接或一个时文ӞQ而后台线E结束时q些资源没有被关闭或删除׃D问题?br /><br />对于q个问题Q我制定规则Q Java 虚拟机在下列情况下不关闭应用E序Q有M非后台线E正在运行,或者: 有Q何后台线E正在执行一个 synchronized Ҏ或 synchronized 代码块?br /><br />后台U程在它执行完synchronized 块或 synchronized Ҏ后可被立卛_闭?br /><br /><strong>重新引入stop() 、 suspend() 和 resume() 关键?/strong><br /><br />׃实用原因q也怸可行Q但是我希望不要废除stop() (在 Thread 和 ThreadGroup ?。但是,我会改变 stop() 的语义,使得调用它时不会破坏已有代码。但是,关于 stop() 的问题,误住,当线E终止后Q stop() 释放所有锁Q这样可能潜在地使正在此对象上工作的U程q入一U不E_Q局部修改)的状态。由于停止的U程已释攑֮在此对象上的所有锁Q所以这些对象无法再被访问?br /><br />对于q个问题Q可以重新定义stop() 的行为,使线E只有在不占有Q何锁时才立即l止。如果它占据着锁,我徏议在此线E释放最后一个锁后才l止它。可以用一个和抛出异常怼的机制来实现此行为。被停止U程应设|一个标志,q且当退出所有同步块时立x试此标志。如果设|了此标志,抛Z个隐式的异常Q但是此异常应不再能被捕捉ƈ且当U程l束时不会生Q何输出。注意,微Y的 NT 操作pȝ不能很好地处理一个外部指C的H然停止(abrupt)。(它不把 stop 消息通知动态连接库Q所以可能导致系l的资源漏z。)q就是我使用cM异常的方法简单地D run() q回的原因?br /><br />与这U和异常cM的处理方法带来的实际问题是,你必需在每个synchronized 块后都插入代码来试"stopped"标志。ƈ且这U附加的代码会降低系l性能q增加代码长度。我惛_的另外一个办法是使 stop() 实现一?延迟?lazy)"停止Q在q种情况下,在下ơ调用 wait() 或 yield() 时才l止。我q想向 Thread 中加入一个 isStopped() 和 stopped() ҎQ此Ӟ Thread 像 isInterrupted() 和 interrupted() 一样工作,但是会检?stop-requested"的状?。这U方法不向第一U那样通用Q但是可行ƈ且不会生过载?br /><br />应把suspend() 和 resume() Ҏ攑֛刊WJava ~程语言中,它们是很有用的,我不惌当成是幼儿园的小孩。由于它们可能生潜在的危险Q当被挂hQ一个线E可以占据一个锁Q而去掉它们是没有道理的。请让我自己来决定是否用它们。如果接收的U程正占据着锁,Sun 公司应该把它们作用 suspend() 的一个运行时间异常处?run-time exception)Q或者更好的Ҏ是,延迟实际的挂赯E,直到U程释放所有的锁?br /><br /><strong>被阻断的 I/O 应正工?/strong><br /><br />应该能打断Q何被L的操作,而不是只让它们wait() 和 sleep() 。我? Taming Java Threads "的第二章中的 socket 部分讨论了此问题。但是现在,对于一个被L的 socket 上的 I/O 操作Q打断它的唯一办法是关闭这个 socketQ而没有办法打断一个被L的文件 I/O 操作。例如,一旦开始一个读hq且q入L状态后Q除非到它实际读Z些东西,否则U程一直出于阻断状态。既使关掉文件句柄也不能打断L作?br /><br />q有Q程序应支持 I/O 操作的超时。所有可能出现阻断操作的对象Q例如 InputStream 对象Q也都应支持q种ҎQ?br /><br />q和 Socket cȝsetSoTimeout(time) Ҏ是等L。同样地Q应该支持把时作ؓ参数传递到L的调用?br /><br />ThreadGroupc?br /><br />ThreadGroup应该实现 Thread 中能够改变线E状态的所有方法。我特别惌它实玊Wjoin() ҎQ这h可{待l中的所有线E的l止?br /><br /><strong>ȝ</strong><br /><br />以上是我的徏议。就像我在标题中所说的那样Q如果我是国?..Q哎Q。我希望q些改变Q或其它{同的方法)最l能被引入 Java 语言中。我实认ؓ Java 语言是一U伟大的~程语言Q但是我也认为 Java 的线E模型设计得q不够完善,q是一件很可惜的事情。但是,Java ~程语言正在演变Q所以还有可提高的前景?br /><br />参考资料本文是对 Taming Java Threads 的更新摘~。该书探讨了在 Java 语言中多U程~程的陷阱和问题Qƈ提供了一个与U程相关的 Java E序包来解决q些问题。 马里兰大学的 Bill Pugh 正在致力修改 JLS 来提高其U程模型。Bill 的提议ƈ不如本文所推荐的那么广Q他主要致力于让现有的线E模型以更ؓ合理方式q行。更多信息可从 www.cs.umd.edu/~pugh/java/memoryModel/ 获得。 从 Sun |站 可找到全部 Java 语言的规范。 要从一个纯技术角度来审视U程Q参阅 Doug Lea ~著的 Concurrent Programming in Java: Design Principles and Patterns W二版 。这是本很棒的书Q但是它的风格是非常学术化的q不一定适合所有的读者。对《 Taming Java Threads 》是个很好的补充ȝ。 由 Scott Oaks 和 Henry Wong ~写的 Java Threads 比 Taming Java Threads 要轻量些Q但是如果您从未~写q线E程序这本书更ؓ适合。Oaks 和 Wong 同样实现了 Holub 提供的帮助类Q而且看看对同一问题的不同解x案L有益的。 由 Bill Lewis 和 Daniel J. Berg ~写的 Threads Primer: A Guide to Multithreaded Programming 是对U程(不限于 Java)的很好入门介l。 Java U程的一些技术信息可在 Sun |站 上找到。 在 "Multiprocessor Safety and Java" 中 Paul Jakubik 讨论了多U程pȝ的 SMP 问题 </font> </p> <img src ="http://www.tkk7.com/errorfun/aggbug/86532.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/errorfun/" target="_blank">errorfun</a> 2006-12-09 13:50 <a href="http://www.tkk7.com/errorfun/articles/86532.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Java U程应该注意的问?/title><link>http://www.tkk7.com/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.tkk7.com/errorfun/articles/86531.html</guid><wfw:comment>http://www.tkk7.com/errorfun/comments/86531.html</wfw:comment><comments>http://www.tkk7.com/errorfun/articles/86531.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/errorfun/comments/commentRss/86531.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/errorfun/services/trackbacks/86531.html</trackback:ping><description><![CDATA[ <font size="2"> <strong>1Q同步对象的恒定?/strong>All java objects are references. </font> <p> <font size="2">  对于局部变量和参数来说Qjava里面的int, float, double, boolean{基本数据类型,都在栈上。这些基本类型是无法同步的;java里面的对象(根对象是ObjectQ,全都在堆里,指向对象的reference在栈上?/font> </p> <p> <font size="2">  java中的同步对象Q实际上是对于reference所指的“对象地址”进行同步?/font> </p> <p> <font size="2">  需要注意的问题是,千万不要对同步对象重新赋倹{D个例子?/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.tkk7.com/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.tkk7.com/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.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_27_226_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_73_221_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />     </span> <span style="COLOR: #0000ff">for</span> <span style="COLOR: #000000">(<img src="http://www.tkk7.com/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.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_89_213_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_118_204_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000"> do something<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000"> <img src="http://www.tkk7.com/images/dot.gif" /> </span> <span style="COLOR: #008000"> <br /> <img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /> </span> <span style="COLOR: #000000"> <br /> <img src="http://www.tkk7.com/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.tkk7.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />          }</span> </span> <span style="COLOR: #000000"> <br /> <img src="http://www.tkk7.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />       }</span> </span> <span style="COLOR: #000000">   <br /><img src="http://www.tkk7.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />   }</span> </span> <span style="COLOR: #000000">   <br /><img src="http://www.tkk7.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span> </span> <span style="COLOR: #000000"> <br /> <img src="http://www.tkk7.com/images/OutliningIndicators/None.gif" align="top" /> </span> </div> <p> <font size="2">   run函数里面的这D同步代码实际上是毫无意义的。因为每一ơlock都给重新分配了新的对象的referenceQ每个线E都在新的reference同步?/font> </p> <p> <font size="2">  大家可能觉得奇怪,怎么会Dq么一个例子。因为我见过q样的代码,同步对象在其它的函数里被重新赋了新倹{?/font> </p> <p> <font size="2">  q种问题很难查出来?/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 设计模式来获取同步对象,也是一U很好的选择?/font> </p> <p> <font size="2">  <strong>2Q如何放|共享数?/strong>实现U程Q有两种ҎQ一U是l承Threadc,一U是实现Runnable接口?/font> </p> <p> <font size="2">  上面丄例子Q采用实现Runnable接口的方法。本文推荐这U方法?/font> </p> <p> <font size="2">  首先Q把需要共享的数据攑֜一个实现Runnable接口的类里面Q然后,把这个类的实例传l多个Thread的构造方法。这P新创建的多个ThreadQ都共同拥有一个Runnable实例Q共享同一份数据?/font> </p> <p> <font size="2">  如果采用l承ThreadcȝҎQ就只好使用static静态成员了。如果共享的数据比较多,需要大量的static静态成员,令程序数据结构؜乱,难以扩展。这U情况应该尽量避免?/font> </p> <p> <font size="2">  ~写一D多U程代码Q处理一个稍微复杂点的问题。两U方法的优劣Q一试便知?/font> </p> <p> <font size="2">  <strong>3Q同步的_度</strong>U程同步的粒度越越好,卻IU程同步的代码块小好。尽量避免用synchronized修饰W来声明Ҏ。尽量用synchronized(anObject)的方式,如果不想引入新的同步对象Q用synchronized(this)的方式。而且Qsynchronized代码块越越好?/font> </p> <p> <font size="2">  <strong>4Q线E之间的通知</strong>q里使用“通知”这个词Q而不用“通信”这个词Q是Z避免词义的扩大化?/font> </p> <p> <font size="2">  U程之间的通知Q通过Object对象的wait()和notify() 或notifyAll() Ҏ实现?/font> </p> <p> <font size="2">  下面用一个例子,来说明其工作原理Q?/font> </p> <p> <font size="2">  假设有两个线E,A和B。共同拥有一个同步对象,lock?/font> </p> <p> <font size="2">  1Q首先,U程A通过synchronized(lock) 获得lock同步对象Q然后调用lock.wait()函数Q放弃lock同步对象Q线EA停止q行Q进入等待队列?/font> </p> <p> <font size="2">  2Q线EB通过synchronized(lock) 获得U程A攑ּ的lock同步对象Q做完一定的处理Q然后调?lock.notify() 或者lock.notifyAll() 通知{待队列里面的线EA?/font> </p> <p> <font size="2">  3Q线EA从等待队列里面出来,q入ready队列Q等待调度?/font> </p> <p> <font size="2">  4Q线EBl箋处理Q出了synchronized(lock)块之后,攑ּlock同步对象?/font> </p> <p> <font size="2">  5Q线EA获得lock同步对象Ql运行?/font> </p> <p> <font size="2">  例子代码如下Q?/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.tkk7.com/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.tkk7.com/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.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_47_1321_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_100_1321_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000"> 获取当前U程的名U?/span> <span style="COLOR: #008000"> <br /> <img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /> </span> <span style="COLOR: #000000"> <br /> <img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_206_1317_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/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">U程A通过synchronized(lock) 获得lock同步对象</span> <span style="COLOR: #008000"> <br /> <img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_274_392_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  System.out.println(“ A gives up lock.?;<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  lock.wait(); </span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000"> 调用lock.wait()函数Q放弃lock同步对象Q?br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000"> U程A停止q行Q进入等待队列?/span> <span style="COLOR: #008000"> <br /> <img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/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"> U程A重新获得lock同步对象之后Ql运行?/span> <span style="COLOR: #008000"> <br /> <img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /> </span> <span style="COLOR: #000000"> <br /> <img src="http://www.tkk7.com/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.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/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">U程B通过synchronized(lock) 获得U程A攑ּ的lock同步对象</span> <span style="COLOR: #008000"> <br /> <img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /> </span> <span style="COLOR: #000000"> <br /> <img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  System.out.println(“B got lock.?;<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  lock.notify(); </span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">通知{待队列里面的线EAQ进入ready队列Q等待调度?br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">U程Bl箋处理Q出了synchronized(lock)块之后,攑ּlock同步对象?/span> <span style="COLOR: #008000"> <br /> <img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /> </span> <span style="COLOR: #000000"> <br /> <img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  System.out.println(“B gives up lock.?;<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/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.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /> </span> <span style="COLOR: #000000"> <br /> <img src="http://www.tkk7.com/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.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /> </span> <span style="COLOR: #000000"> <br /> <img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_1060_1313_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/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.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/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(resourceQ”A?;<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  A.start();<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  </span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000"> ȝE停止运行,以便U程A开始运行?/span> <span style="COLOR: #008000"> <br /> <img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/images/dot.gif" /> </span> <span id="Codehighlighter1_1195_1222_Open_Text"> <span style="COLOR: #000000">{<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" />  Thread.sleep(</span> <span style="COLOR: #000000">500</span> <span style="COLOR: #000000">);<br /><img src="http://www.tkk7.com/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.tkk7.com/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.tkk7.com/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.tkk7.com/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(resourceQ”B?;<br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/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.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.tkk7.com/images/OutliningIndicators/InBlock.gif" align="top" /></span> </span> </span> </div> <p> <br /> <font size="2">   <strong>5Q跨cȝ同步对象</strong>对于单的问题Q可以把讉K׃n资源的同步代码都攑֜一个类里面?/font> </p> <p> <font size="2">  但是对于复杂的问题,我们需要把问题分ؓ几个部分来处理,需要几个不同的cL处理问题。这Ӟ需要在不同的类中,׃n同步对象。比如,在生产者和消费者之间共享同步对象,在读者和写者之间共享同步对象?/font> </p> <p> <font size="2">  如何在不同的cMQ共享同步对象。有几种Ҏ实现Q?/font> </p> <p> <font size="2">  Q?Q前面讲q的ҎQ用static静态成员,Q或者用Singleton Pattern.Q?/font> </p> <p> <font size="2">  Q?Q用参数传递的ҎQ把同步对象传递给不同的类?/font> </p> <p> <font size="2">  Q?Q利用字W串帔R的“原子性”?/font> </p> <p> <font size="2">  对于W三U方法,q里做一下解释。一般来_E序代码中的字符串常量经q编译之后,都具有唯一性,卻I内存中不会存在两份相同的字符串常量?/font> </p> <p> <font size="2">  Q通常情况下,C QC语言E序~译之后Q也h同样的特性。)</font> </p> <p> <font size="2">  比如Q我们有如下代码?/font> </p> <p> <font size="2">  String A = “atom?</font> </p> <p> <font size="2">  String B = “atom?</font> </p> <p> <font size="2">  我们有理p为,A和B指向同一个字W串帔R。即QA==B?/font> </p> <p> <font size="2">  注意Q声明字W串变量的代码,不符合上面的规则?/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">  q里的C和D的声明是字符串变量的声明Q所以,C != D?/font> </p> <p> <font size="2">  有了上述的认识,我们可以用字W串帔R作ؓ同步对象?/font> </p> <p> <font size="2">  比如我们在不同的cMQ用synchronized(“myLock?, “myLock?wait(),“myLock?notify(), q样的代码,p够实C同类之间的线E同步?/font> </p> <p> <font size="2">  本文q不强烈推荐q种用法Q只是说明,有这样一U方法存在?/font> </p> <p> <font size="2">  本文推荐W二U方法,Q?Q用参数传递的ҎQ把同步对象传递给不同的类?/font> </p> <!--正文--> <img src ="http://www.tkk7.com/errorfun/aggbug/86531.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/errorfun/" target="_blank">errorfun</a> 2006-12-09 13:45 <a href="http://www.tkk7.com/errorfun/articles/86531.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Java的垃圑֛收机制详解和调优http://www.tkk7.com/errorfun/articles/86528.htmlerrorfunerrorfunSat, 09 Dec 2006 05:39:00 GMThttp://www.tkk7.com/errorfun/articles/86528.htmlhttp://www.tkk7.com/errorfun/comments/86528.htmlhttp://www.tkk7.com/errorfun/articles/86528.html#Feedback0http://www.tkk7.com/errorfun/comments/commentRss/86528.htmlhttp://www.tkk7.com/errorfun/services/trackbacks/86528.html 1.JVM的gc概述

  gc卛_圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存。java语言q不要求jvm有gcQ也没有规定gc如何工作。不q常用的jvm都有gcQ而且大多数gc都用类似的法理内存和执行收集操作?/font>

  在充分理解了垃圾攉法和执行过E后Q才能有效的优化它的性能。有些垃圾收集专用于Ҏ的应用程序。比如,实时应用E序主要是ؓ了避免垃圾收集中断,而大多数OLTP应用E序则注重整体效率。理解了应用E序的工作负荷和jvm支持的垃圾收集算法,便可以进行优化配|垃圾收集器?br />
  垃圾攉的目的在于清除不再用的对象。gc通过定对象是否被活动对象引用来定是否攉该对象。gc首先要判断该对象是否是时候可以收集。两U常用的Ҏ是引用计数和对象引用遍历?br />
  1.1.引用计数

  引用计数存储对特定对象的所有引用数Q也是_当应用程序创建引用以及引用超围时Qjvm必须适当增减引用数。当某对象的引用Cؓ0Ӟ便可以进行垃圾收集?br />
  1.2.对象引用遍历

  早期的jvm使用引用计数Q现在大多数jvm采用对象引用遍历。对象引用遍历从一l对象开始,沿着整个对象图上的每条链接,递归定可到达(reachableQ的对象。如果某对象不能从这些根对象的一个(臛_一个)到达Q则它作ؓ垃圾攉。在对象遍历阶段Qgc必须C哪些对象可以到达Q以便删除不可到辄对象Q这UCؓ标记QmarkingQ对象?br />
  下一步,gc要删除不可到辄对象。删除时Q有些gc只是单的扫描堆栈Q删除未标记的未标记的对象,q攑֮们的内存以生成新的对象,q叫做清除(sweepingQ。这U方法的问题在于内存会分成好多小D,而它们不以用于新的对象Q但是组合v来却很大。因此,许多gc可以重新l织内存中的对象Qƈq行压羃QcompactQ,形成可利用的I间?br />
  为此Qgc需要停止其他的zdzd。这U方法意味着所有与应用E序相关的工作停止,只有gcq行。结果,在响应期间增减了许多hh。另外,更复杂的gc不断增加或同时运行以减少或者清除应用程序的中断。有的gc使用单线E完成这工作,有的则采用多U程以增加效率?br />
  2.几种垃圾回收机制

  2.1.标记Q清除收集器

  q种攉器首先遍历对象图q标记可到达的对象,然后扫描堆栈以寻找未标记对象q攑֮们的内存。这U收集器一般用单U程工作q停止其他操作?br />
  2.2.标记Q压~收集器

  有时也叫标记Q清除-压羃攉器,与标讎ͼ清除攉器有相同的标记阶Dc在W二阶段Q则把标记对象复制到堆栈的新域中以便压羃堆栈。这U收集器也停止其他操作?br />
  2.3.复制攉?br />
  q种攉器将堆栈分ؓ两个域,常称为半I间。每ơ仅使用一半的I间Qjvm生成的新对象则放在另一半空间中。gcq行Ӟ它把可到辑֯象复制到另一半空_从而压~了堆栈。这U方法适用于短生存期的对象Q持l复刉生存期的对象则导致效率降低?br />
  2.4.增量攉?br />
  增量攉器把堆栈分ؓ多个域,每次仅从一个域攉垃圾。这会造成较小的应用程序中断?br />
  2.5.分代攉?br />
  q种攉器把堆栈分ؓ两个或多个域Q用以存放不同寿命的对象。jvm生成的新对象一般放在其中的某个域中。过一D|_l箋存在的对象将获得使用期ƈ转入更长寿命的域中。分代收集器对不同的域用不同的法以优化性能?br />
  2.6.q发攉?br />
  q发攉器与应用E序同时q行。这些收集器在某点上Q比如压~时Q一般都不得不停止其他操作以完成特定的Q务,但是因ؓ其他应用E序可进行其他的后台操作Q所以中断其他处理的实际旉大大降低?br />
  2.7.q行攉?br />
  q行攉器用某U传l的法q用多U程q行的执行它们的工作。在多cpu机器上用多U程技术可以显著的提高java应用E序的可扩展性?br />
  3.Sun HotSpot

  1.4.1 JVM堆大的调整

  Sun HotSpot 1.4.1使用分代攉器,它把堆分Z个主要的域:新域、旧域以及永久域。Jvm生成的所有新对象攑֜新域中。一旦对象经历了一定数量的垃圾攉循环后,便获得用期q进入旧域。在怹域中jvm则存储class和method对象。就配置而言Q永久域是一个独立域q且不认为是堆的一部分?br />
  下面介绍如何控制q些域的大小。可使用-Xms?Xmx 控制整个堆的原始大小或最大倹{?br />
  下面的命令是把初始大设|ؓ128MQ?br />
  java –Xms128m

  –Xmx256m为控制新域的大小Q可使用-XX:NewRatio讄新域在堆中所占的比例?br />
  下面的命令把整个堆设|成128mQ新域比率设|成3Q即新域与旧域比例ؓ1Q?Q新域ؓ堆的1/4?2MQ?br />
java –Xms128m –Xmx128m
–XX:NewRatio =3可?XX:NewSize?XX:MaxNewsize讄新域的初始值和最大倹{?br />
  下面的命令把新域的初始值和最大D|成64m:

java –Xms256m –Xmx256m –Xmn64m

  怹域默认大ؓ4m。运行程序时Qjvm会调整永久域的大以满需要。每ơ调整时Qjvm会对堆进行一ơ完全的垃圾攉?br />
  使用-XX:MaxPerSize标志来增加永久域搭大。在WebLogic Server应用E序加蝲较多cLQ经帔R要增加永久域的最大倹{当jvm加蝲cLQ永久域中的对象急剧增加Q从而jvm不断调整怹域大。ؓ了避免调_可?XX:PerSize标志讄初始倹{?br />
  下面把永久域初始D|成32mQ最大D|成64m?br />
java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m

  默认状态下QHotSpot在新域中使用复制攉器。该域一般分Z个部分。第一部分为EdenQ用于生成新的对象。另两部分称为救助空_当Eden充满Ӟ攉器停止应用程序,把所有可到达对象复制到当前的from救助I间Q一旦当前的from救助I间充满Q收集器则把可到辑֯象复制到当前的to救助I间。From和to救助I间互换角色。维持活动的对象在救助I间不断复制Q直到它们获得用期q{入旧域。?XX:SurvivorRatio可控制新域子I间的大?br />
  同NewRation一PSurvivorRation规定某救助域与EdenI间的比倹{比如,以下命o把新域设|成64mQEden?2mQ每个救助域各占16mQ?br />
java -Xms256m -Xmx256m -Xmn64m -XX:SurvivorRation =2

  如前所qͼ默认状态下HotSpotҎ域用复制收集器Q对旧域使用标记Q清除-压羃攉器。在新域中用复制收集器有很多意义,因ؓ应用E序生成的大部分对象是短寿命的。理想状态下Q所有过渡对象在UdEdenI间时将被收集。如果能够这L话,q且UdEdenI间的对象是长寿命的Q那么理Z可以立即把它们移q旧域,避免在救助空间反复复制。但是,应用E序不能适合q种理想状态,因ؓ它们有一部分中长寿命的对象。最好是保持q些中长寿命的对象ƈ攑֜新域中,因ؓ复制部分的对象L压羃旧域廉h。ؓ控制新域中对象的复制Q可?XX:TargetSurvivorRatio控制救助I间的比例(该值是讄救助I间的用比例。如救助I间?MQ该?0表示可用500KQ。该值是一个百分比Q默认值是50。当较大的堆栈用较低的sruvivorratioӞ应增加该值到80?0Q以更好利用救助I间。用-XX:maxtenuring threshold可控制上限?br />
  为放|所有的复制全部发生以及希望对象从eden扩展到旧域,可以把MaxTenuring Threshold讄?。设|完成后Q实际上׃再用救助空间了Q因此应把SurvivorRatio设成最大g最大化EdenI间Q设|如下:

java ?-XX:MaxTenuringThreshold=0 –XX:SurvivorRatioQ?0000 ?br />
  4.BEA JRockit JVM的?br />
  Bea WebLogic 8.1使用的新的JVM用于Intelq_。在Bea安装完毕的目录下可以看到有一个类gjrockit81sp1_141_03的文件夹。这是Bea新JVM所在目录。不同于HotSpot把Java字节码编译成本地码,它预先编译成cRJRockitq提供了更细致的功能用以观察JVM的运行状态,主要是独立的GUI控制収ͼ只能适用于用Jrockit才能使用jrockit81sp1_141_03自带的console监控一些cpu及memory参数Q或者WebLogic Server控制台?br />
  Bea JRockit JVM支持4U垃圾收集器Q?br />
  4.1.1.分代复制攉?

  它与默认的分代收集器工作{略cM。对象在新域中分配,即JRockit文档中的nursery。这U收集器最适合单cpuZ型堆操作?br />
  4.1.2.单空间ƈ发收集器

  该收集器使用完整堆,q与背景U程共同工作。尽这U收集器可以消除中断Q但是收集器需p较长的时间寻找死对象Q而且处理应用E序时收集器l常q行。如果处理器不能应付应用E序产生的垃圾,它会中断应用E序q关闭收集?br />
  分代q发攉?q种攉器在护理域用排它复制收集器Q在旧域中则使用q发攉器。由于它比单I间共同发生攉器中断频J,因此它需要较的内存Q应用程序的q行效率也较高,注意Q过的护理域可以导致大量的临时对象被扩展到旧域中。这会造成攉器超负荷q作Q甚至采用排它性工作方式完成收集?br />
  4.1.3.q行攉?br />
  该收集器也停止其他进E的工作Q但使用多线E以加速收集进E。尽它比其他的攉器易于引起长旉的中断,但一般能更好的利用内存,E序效率也较高?br />
  默认状态下QJRockit使用分代q发攉器。要改变攉器,可?Xgc:<gc_name>Q对应四个收集器分别为gencopyQsingleconQgencon以及parallel。可使用-Xms?Xmx讄堆的初始大小和最大倹{要讄护理域,则?Xns:java –jrockit –Xms512m –Xmx512m –Xgc:gencon –Xns128m…尽JRockit支持-verbose:gc开养I但它输出的信息会因收集器的不同而异。JRockitq支持memory、load和codegen的输出?br />
  注意 Q如?使用JRockit JVM的话q可以用WLS自带的consoleQC:\bea\jrockit81sp1_141_03\bin下)来监控一些数据,如cpuQmemery{。要惌构监控必d启动服务时startWeblogic.cmd中加入-Xmanagement参数?br />
  5.如何从JVM中获取信息来q行调整

  -verbose.gc开兛_昄gc的操作内宏V打开它,可以昄最忙和最I闲攉行ؓ发生的时间、收集前后的内存大小、收集需要的旉{。打开-xx:+ printgcdetails开养I可以详细了解gc中的变化。打开-XX: + PrintGCTimeStamps开养I可以了解q些垃圾攉发生的时_自jvm启动以后以秒计量。最后,通过-xx: + PrintHeapAtGC开关了解堆的更详细的信息。ؓ了了解新域的情况Q可以通过-XX:=PrintTenuringDistribution开关了解获得用期的对象权?br />
  6.PdmpȝJVM调整

  6.1.服务器:前提内存1G 单CPU

  可通过如下参数q行调整Q-server 启用服务器模式(如果CPU多,服务器机使用此项Q?br />
  QXms,QXmx一般设为同样大?800m

  QXmn 是将NewSize与MaxNewSize设ؓ一致?20m

  QXX:PerSize 64m

  QXX:NewSize 320m 此D大可调大新对象区Q减Full GCơ数

  QXX:MaxNewSize 320m

  QXX:NewRato NewSize设了可不设?br />
  QXX: SurvivorRatio

  QXX:userParNewGC 可用来设|ƈ行收?

  QXX:ParallelGCThreads 可用来增加ƈ行度

  QXXUseParallelGC 讄后可以用ƈ行清除收集器

  QXXQUseAdaptiveSizePolicy 与上面一个联合用效果更好,利用它可以自动优化新域大以及救助空间比?br />
  6.2.客户机:通过在JNLP文g中设|参数来调整客户端JVM

  JNLP中参敎ͼinitial-heap-size和max-heap-size

  q可以在framework的RequestManager中生成JNLP文g时加入上q参敎ͼ但是q些值是要求Ҏ客户机的g状态变化的Q如客户机的内存大小{)。徏议这两个参数D为客h可用内存?0Q(有待试Q。ؓ了在动态生成JNLP时以上两个参数D够随客户Z同而不同,可靠虑获得客hpȝ信息q将q些嵌到首页index.jsp中作接请求的参数?br />
  在设|了上述参数后可以通过Visualgc 来观察垃圑֛收的一些参数状态,再做相应的调整来改善性能。一般的标准是减fullgc的次敎ͼ最好硬件支持用ƈ行垃圑֛Ӟ要求多CPUQ?



errorfun 2006-12-09 13:39 发表评论
]]>
[转]探讨JAVA内存泄漏原因和检工?/title><link>http://www.tkk7.com/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.tkk7.com/errorfun/articles/86527.html</guid><wfw:comment>http://www.tkk7.com/errorfun/comments/86527.html</wfw:comment><comments>http://www.tkk7.com/errorfun/articles/86527.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/errorfun/comments/commentRss/86527.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/errorfun/services/trackbacks/86527.html</trackback:ping><description><![CDATA[原文出处Q?a 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 />        虽然垃圾攉器处理了大多数内存管理问题,从而ɾ~程人员的生zd得更L了,但是~程人员q是可能犯错而导致出现内存问题。简单地_GC循环地跟t所有来自“根”对象(堆栈对象、静态对象、JNI句柄指向的对象,诸如此类Q的引用Qƈ所有它所能到辄对象标记为活动的。程序只可以操纵q些对象Q其他的对象都被删除了。因为GC使程序不可能到达已被删除的对象,q么做就是安全的? <p><font size="3">  虽然内存理可以说是自动化的Q但是这q不能ɾ~程人员免受思考内存管理问题之苦。例如,分配Q以及释放)内存M有开销Q虽然这U开销对编Eh员来说是不可见的。创Z太多对象的程序将会比完成同样的功能而创建的对象却比较少的程序更慢一些(在其他条件相同的情况下)?/font></p><p><font size="3">  而且Q与本文更ؓ密切相关的是Q如果忘记“释䏀先前分配的内存Q就可能造成内存泄漏。如果程序保留对永远不再使用的对象的引用Q这些对象将会占用ƈ耗尽内存Q这是因动化的垃圾收集器无法证明q些对象不再用。正如我们先前所说的Q如果存在一个对对象的引用,对象p定义为活动的Q因此不能删除。ؓ了确保能回收对象占用的内存,~程人员必须保该对象不能到达。这通常是通过对象字D设|ؓnull或者从集合(collection)中移除对象而完成的。但是,注意Q当局部变量不再用时Q没有必要将其显式地讄为null。对q些变量的引用将随着Ҏ的退自动清除?/font></p><p><font size="3">  概括地说Q这是内存托管语言中的内存泄漏产生的主要原因:保留下来却永q不再用的对象引用?/font></p><p><font size="3">典型泄漏</font></p><p><font size="3">  既然我们知道了在Java中确实有可能发生内存泄漏Q就让我们来看一些典型的内存泄漏及其原因?/font></p><p><font size="3">全局集合</font></p><p><font size="3">  在大的应用程序中有某U全局的数据储存库是很常见的,例如一个JNDI树或一个会话表。在q些情况下,必须注意理储存库的大小。必L某种机制从储存库中移除不再需要的数据?/font></p><p><font size="3">  q可能有多种ҎQ但是最常见的一U是周期性运行的某种清除d。该d验证储存库中的数据QƈU除M不再需要的数据?/font></p><p><font size="3">  另一U管理储存库的方法是使用反向链接(referrer)计数。然后集合负责统计集合中每个入口的反向链接的数目。这要求反向链接告诉集合何时会退出入口。当反向链接数目为零Ӟ该元素就可以从集合中U除了?/font></p><p><font size="3">~存</font></p><p><font size="3">  ~存是一U数据结构,用于快速查扑ַl执行的操作的结果。因此,如果一个操作执行v来很慢,对于常用的输入数据,可以将操作的结果缓存,q在下次调用该操作时使用~存的数据?/font></p><p><font size="3">  ~存通常都是以动态方式实现的Q其中新的结果是在执行时d到缓存中的。典型的法是:</font></p><p><font size="3">查结果是否在~存中,如果在,p回结果?<br />如果l果不在~存中,p行计?<br />计出来的l果d到缓存中Q以便以后对该操作的调用可以使用?<br />  该算法的问题Q或者说是潜在的内存泄漏Q出在最后一步。如果调用该操作时有相当多的不同输入Q就有相当多的l果存储在缓存中。很明显q不是正的Ҏ?/font></p><p><font size="3">  Z预防q种h潜在破坏性的设计Q程序必ȝ保对于缓存所使用的内存容量有一个上限。因此,更好的算法是Q?/font></p><p><font size="3">查结果是否在~存中,如果在,p回结果?<br />如果l果不在~存中,p行计?<br />如果~存所占的I间q大Q就U除~存最久的l果?<br />计出来的l果d到缓存中Q以便以后对该操作的调用可以使用?<br />  通过始终U除~存最久的l果Q我们实际上q行了这L假设Q在来Q比L存最久的数据Q最q输入的数据更有可能用到。这通常是一个不错的假设?/font></p><p><font size="3">  新算法将保~存的容量处于预定义的内存范围之内。确切的范围可能很难计算Q因为缓存中的对象在不断变化Q而且它们的引用包|万象。ؓ~存讄正确的大是一w常复杂的dQ需要将所使用的内存容量与索数据的速度加以q?/font></p><p><font size="3">  解决q个问题的另一U方法是使用java.lang.ref.SoftReferencec跟t缓存中的对象。这U方法保证这些引用能够被U除Q如果虚拟机的内存用而需要更多堆的话?/font></p><p><font size="3">ClassLoader</font></p><p><font size="3">  Java ClassLoaderl构的用ؓ内存泄漏提供了许多可乘之机。正是该l构本n的复杂性ClassLoader在内存泄漏方面存在如此多的问题。ClassLoader的特别之处在于它不仅涉及“常规”的对象引用Q还涉及元对象引用,比如Q字Dc方法和cR这意味着只要有对字段、方法、类或ClassLoader的对象的引用QClassLoader׃ȝ在JVM中。因为ClassLoader本n可以兌许多cd光态字D,所以就有许多内存被泄漏了?/font></p><p><font size="3">定泄漏的位|?/font></p><p><font size="3">  通常发生内存泄漏的第一个迹象是Q在应用E序中出COutOfMemoryError。这通常发生在您最不愿意它发生的生产环境中Q此时几乎不能进行调试。有可能是因为测试环境运行应用程序的方式与生产系l不完全相同Q因而导致泄漏只出现在生产中。在q种情况下,需要用一些开销较低的工h监控和查扑ֆ存泄漏。还需要能够无需重启pȝ或修改代码就可以这些工兯接到正在q行的系l上。可能最重要的是Q当q行分析Ӟ需要能够断开工具而保持系l不受干扰?/font></p><p><font size="3">  虽然OutOfMemoryError通常都是内存泄漏的信P但是也有可能应用E序实正在使用q么多的内存Q对于后者,或者必d加JVM可用的堆的数量,或者对应用E序q行某种更改Q它用较的内存。但是,在许多情况下QOutOfMemoryError都是内存泄漏的信受一U查明方法是不间断地监控GC的活动,定内存使用量是否随着旉增加。如果确实如此,可能发生了内存泄漏?/font></p><p><font size="3">详细输出</font></p><p><font size="3">  有许多监控垃圾收集器zd的方法。而其中用最q泛的可能是使用-Xverbose:gc选项启动JVMQƈ观察输出?/font></p><p><font size="3">[memory ] 10.109-10.235: GC 65536K->16788K (65536K), 126.000 ms <br /> 头后面的|本例中是16788KQ是垃圾攉所使用的堆的容量?/font></p><p><font size="3">控制?/font></p><p><font size="3">  查看q箋不断的GC的详l统计信息的输出是非常乏味的。幸好有q方面的工具。JRockit Management Console可以昄堆用量的图C。借助于该图,可以很容易地看出堆用量是否随时间增加?/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">?. JRockit Management Console</font></p><p><font size="3">  甚至可以配置该管理控制台Q以便如果发生堆使用量过大的情况Q或Z其他的事ӞQ控制台能够向您发送电子邮件。这明显使内存泄漏的查看变得更容易了?/font></p><p><font size="3">内存泄漏工?/font></p><p><font size="3">  q有其他的专门进行内存泄漏检的工具。JRockit Memory Leak Detector可以用来查看内存泄漏Qƈ可以更深入地查出泄漏的根源。这个强大的工具是紧密集成到JRockit JVM中的Q其开销非常,对虚拟机的堆的访问也很容易?/font></p><p><font size="3">专业工具的优?/font></p><p><font size="3">  一旦知道确实发生了内存泄漏Q就需要更专业的工h查明Z么会发生泄漏。JVM自己是不会告诉您的。这些专业工具从JVM获得内存pȝ信息的方法基本上有两U:JVMTI和字节码技?byte code instrumentation)。Java虚拟机工h?Java Virtual Machine Tools InterfaceQJVMTI)及其前nJava虚拟机监视程序接?Java Virtual Machine Profiling InterfaceQJVMPI)是外部工具与JVM通信q从JVM攉信息的标准化接口。字节码技术是指用探器处理字节码以获得工具所需的信息的技术?/font></p><p><font size="3">  对于内存泄漏来_q两U技术有两个~点Q这使它们不太适合用于生环境。首先,它们在内存占用和性能降低斚w的开销不可忽略。有兛_使用量的信息必须以某U方式从JVM导出Qƈ攉到工具中q行处理。这意味着要ؓ工具分配内存。信息的导出也媄响了JVM的性能。例如,当收集信息时Q垃圾收集器运行得比较慢。另外一个缺Ҏ需要始l将工具q在JVM上。这是不可能的:工兯在一个已l启动的JVM上,q行分析Q断开工具Qƈ保持JVMq行?/font></p><p><font size="3">  因ؓJRockit Memory Leak Detector是集成到JVM中的Q就没有q两个缺点了。首先,许多处理和分析工作是在JVM内部q行的,所以没有必要{换或重新创徏M数据。处理还可以背负(piggyback)在垃圾收集器本n上而进行,q意味着提高了速度。其ơ,只要JVM是?Xmanagement选项Q允讔R过q程JMX接口监控和管理JVMQ启动的QMemory Leak Detector可以与q行中的JVMq行q接或断开。当该工h开Ӟ没有M东西遗留在JVM中,JVM又将以全速运行代码,正如工具q接之前一栗?/font></p><p><font size="3">势分析</font></p><p><font size="3">  让我们深入地研究一下该工具以及它是如何用来跟踪内存泄漏的。在知道发生内存泄漏之后Q第一步是要弄清楚泄漏了什么数?-哪个cȝ对象引v了泄漏?JRockit Memory Leak Detector是通过在每ơ垃圾收集时计算每个cȝ现有对象的数目来实现q一步的。如果特定类的对象数目随旉而增长(“增长率”)Q就可能发生了内存泄漏?</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 />?. Memory Leak Detector的趋势分析视?/font></p><p><font size="3">  因ؓ泄漏可能像细一样非常小Q所以趋势分析必运行很长一D|间。在短时间内Q可能会发生一些类的局部增长,而之后它们又会跌落。但是趋势分析的开销很小Q最大开销也不q是在每ơ垃圾收集时数据包由JRockit发送到Memory Leak DetectorQ。开销不应该成ZQ何系l的问题——即使是一个全速运行的生中的pȝ?/font></p><p><font size="3">  起初数目会蟩跃不停,但是一D|间之后它们就会稳定下来,q显C出哪些cȝ数目在增ѝ?/font></p><p><font size="3">扑ևҎ原因</font></p><p><font size="3">  有时候知道是哪些cȝ对象在泄漏就以说明问题了。这些类可能只用于代码中的非常有限的部分Q对代码q行一ơ快速检查就可以昄出问题所在。遗憑֜是,很有可能只有q类信息qƈ不够。例如,常见到泄漏出在类java.lang.String的对象上Q但是因为字W串在整个程序中都用,所以这q没有多大帮助?/font></p><p><font size="3">  我们想知道的是,另外q有哪些对象与泄漏对象关联?在本例中是String。ؓ什么泄漏的对象q存在?哪些对象保留了对q些对象的引用?但是能列出的所有保留对String的引用的对象会非常多,以至于没有什么实际用处。ؓ了限制数据的数量Q可以将数据按类分组Q以便可以看出其他哪些对象的cM泄漏对象(String)兌。例如,String在Hashtable中是很常见的Q因此我们可能会看到与String兌的Hashtable数据对象。由Hashtable数据倒推Q我们最l可以找Cq些数据Ҏ关的Hashtable对象以及StringQ如?所C)?</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 />?. 在工具中看到的类型图的示例视?/font></p><p><font size="3">倒推</font></p><p><font size="3">  因ؓ我们仍然是以cȝ对象而不是单独的对象来看待对象,所以我们不知道是哪个Hashtable在泄漏。如果我们可以弄清楚pȝ中所有的Hashtable都有多大Q我们就可以假定最大的Hashtable是正在泄漏的那一个(因ؓ随着旉的流逝它会篏U泄漏而增长得相当大)。因此,一份有x有Hashtable对象以及它们引用了多数据的列表Q将会帮助我们指出造成泄漏的确切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 />?. 界面QHashtable对象以及它们所引用数据的数量的列表</font></p><p><font size="3">  对对象引用数据数目的计算开销非常大(需要以该对象作为根遍历引用图)Q如果必d许多对象都这么做Q将会花很多旉。如果了解一点Hashtable的内部实现原理就可以扑ֈ一条捷径。Hashtable的内部有一个Hashtable数据的数组。该数组随着Hashtable中对象数目的增长而增ѝ因此,为找出最大的HashtableQ我们只需扑և引用Hashtable数据的最大数l。这栯快很多?</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">?. 界面Q最大的Hashtable数据Ҏl及其大的清单</font></p><p><font size="3">更进一?/font></p><p><font size="3">  当找到发生泄漏的Hashtable实例Ӟ我们可以看到其他哪些实例在引用该HashtableQƈ倒推回去看看是哪个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. q就是工具中的实例图</font></p><p><font size="3">  例如Q该Hashtable可能是由MyServercd的对象在名ؓactiveSessions的字D中引用的。这U信息通常p以查找源代码以定位问题所在了?</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 />?. 查对象以及它对其他对象的引用</font></p><p><font size="3">扑և分配位置</font></p><p><font size="3">  当跟t内存泄漏问题时Q查看对象分配到哪里是很有用的。只知道它们如何与其他对象相兌Q即哪些对象引用了它们)是不够的Q关于它们在何处创徏的信息也很有用。当然了Q您q不惛_建应用程序的辅助构gQ以打印每次分配的堆栈跟t?stack trace)。您也不想仅仅ؓ了跟t内存泄漏而在q行应用E序时将一个分析程序连接到生环境中?/font></p><p><font size="3">  借助于JRockit Memory Leak DetectorQ应用程序中的代码可以在分配时进行动态添加,以创建堆栈跟t。这些堆栈跟t可以在工具中进行篏U和分析。只要不启用׃会因该功能而生成本,q意味着随时可以q行分配跟踪。当h分配跟踪ӞJRockit ~译器动态插入代码以监控分配Q但是只针对所h的特定类。更好的是,在进行数据分析时Q添加的代码全部被移除,代码中没有留下Q何会引v应用E序性能降低的更攏V?</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 />?. CZE序执行期间String的分配的堆栈跟踪</font></p><p><font size="3">l束?/font></p><p><font size="3">  内存泄漏是难以发现的。本文重点介l了几种避免内存泄漏的最佛_践,包括要始l记住在数据l构中所攄的内容,以及密切监控内存使用量以发现H然的增ѝ?/font></p><p><font size="3">  我们都已l看CJRockit Memory Leak Detector是如何用于生产中的系l以跟踪内存泄漏的。该工具使用一U三步式的方法来扑և泄漏。首先,q行势分析Q找出是哪个cȝ对象在泄漏。接下来Q看看有哪些其他的类与泄漏的cȝ对象相关联。最后,q一步研I单个对象,看看它们是如何互相关联的。也有可能对pȝ中所有对象分配进行动态的堆栈跟踪。这些功能以及该工具紧密集成到JVM中的Ҏ您可以以一U安全而强大的方式跟踪内存泄漏q进行修复?/font></p><p><font size="3">参考资?/font></p><p><font size="3"><a ><font color="#000066">JRockit工具下蝲</font></a><br /><a ><font color="#000066">BEA JRockit 5.0说明文档</font></a><br /><a ><font color="#000066">JRockit 5.0中的新功能和新工?/font></a><br /><a ><font color="#000066">BEA JRockit DevCenter <br /></font></a></font></p><img src ="http://www.tkk7.com/errorfun/aggbug/86527.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/errorfun/" target="_blank">errorfun</a> 2006-12-09 13:19 <a href="http://www.tkk7.com/errorfun/articles/86527.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Eclipse 启动q行速度调优http://www.tkk7.com/errorfun/articles/86510.htmlerrorfunerrorfunSat, 09 Dec 2006 02:30:00 GMThttp://www.tkk7.com/errorfun/articles/86510.htmlhttp://www.tkk7.com/errorfun/comments/86510.htmlhttp://www.tkk7.com/errorfun/articles/86510.html#Feedback0http://www.tkk7.com/errorfun/comments/commentRss/86510.htmlhttp://www.tkk7.com/errorfun/services/trackbacks/86510.html Eclipse 启动q行速度调优

提高 JAVA IDE 的性能的JVM开?
Submitted by 天?on 2005, August 18, 2:45 PM. integration
我的本本是p4 1.8G的dell c640 内存1GQeclipse 3.1 + myeclipse 4.0m2 速度q不错?/font>

q行参数如下Q?br />eclipse.exe -vmargs -Xverify:none -XX:+UseParallelGC -XX:PermSize=20M

Q-Q-Q-Q-Q-Q-Q-

JVM 提供了各U用于调整内存分配和垃圾回收行ؓ的标准开兛_非标准开兟뀂其中一些设|可以提?JAVA IDE 的性能?
注意Q由?-X Q尤其是 -XX JVMQ开关通常?JVM ?JVM 供应商特定的Q本部分介绍的开兛_用于 Sun Microsystems J2SE 1.4.2?/font>

以下讄在大多数pȝ上将产生比工厂更好的讄性能?
-vmargs - 表示后面的所有参数直接传递到所指示?Java VM?/font>

-Xverify:none - 此开兛_闭Java字节码验证,从而加快了c装入的速度Qƈ使得在仅为验证目的而启动的q程中无需装入cR此开关羃短了启动旉Q因此没有理׃使用它?

-Xms24m - 此设|指C?Java 虚拟机将其初始堆大小讄?24 MB。通过指示 JVM 最初应分配l堆的内存数量,可以?JVM 不必?IDE 占用较多内存时增加堆大小?

-Xmx96m - 此设|指?Java 虚拟机应对堆使用的最大内存数量。ؓ此数量设|上限表C?Java q程消耗的内存数量不得过可用的物理内存数量。对于具有更多内存的pȝ可以增加此限Ӟ96 MB 讄有助于确?IDE 在内存量?128MB ?256MB 的系l上能够可靠地执行操作。注意:不要该D|ؓ接近或大于系l的物理内存量,否则在主要回收q程中导致频J的交换操作?

-XX:PermSize=20m - ?JVM 开关不仅功能更为强大,而且能够~短启动旉。该讄用于调整内存&quot;怹区域&quot;Q类保存在该区域中)的大。因此我们向 JVM 提示它将需要的内存量。该讄消除了许多系l启动过E中的主要垃圾收集事件。SunONE Studio 或其它包含更多模块的 IDE 的用户可能希望将该数D|得更高?
下面列出了其它一些可能对 ECLIPSE 在某些系l(不是所有系l)上的性能产生d或明昑֪响的 JVM 开兟뀂尽用它们会产生一定的影响Q但仍值得一试?

-XX:CompileThreshold=100 - 此开兛_降低启动速度Q原因是与不使用此开关相比,HotSpot 能够更快地将更多的方法编译ؓ本地代码。其l果是提高了 IDE q行时的性能Q这是因为更多的 UI 代码被~译而不是被解释。该DC方法在被编译前必须被调用的ơ数?

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC - 如果垃圾回收频繁中断Q则请尝试用这些开兟뀂此开兛_?JVM 对主要垃圑֛收事Ӟ如果在多处理器工作站上运行,则也适用于次要回收事Ӟ使用不同的算法,q些法不会影响整个垃圾回收q程。注意:目前不定此收集器是提高还是降低单处理器计机的性能?

-XX:+UseParallelGC - 某些试表明Q至在内存配置相当良好的单处理器系l中Q用此回收法可以次要垃圑֛收的持箋旉减半。注意,q是一个矛盄问题Q事实上此回收器主要适用于具有千兆字节堆的多处理器。尚无可用数据表明它对主要垃圑֛收的影响。注意:此回收器?-XX:+UseConcMarkSweepGC 是互斥的?/font>

我的机器?12MB的内?br />下面是我的eclipse启动参数Qeclipse.exe -vmargs -Xverify:none -Xms64M -Xmx256M -XX:PermSize=20M&nbsp; -XX:+UseParallelGC

-----

By BeanSoft:
我的电脑?G内存, 有一ơ内存不了... MyEclipse 推荐我使用一个启动参? 现在我的启动参数?


eclipse.exe -vmargs -Xverify:none -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M -XX:+UseParallelGC



errorfun 2006-12-09 10:30 发表评论
]]>
[转]String帔R之迷http://www.tkk7.com/errorfun/articles/86511.htmlerrorfunerrorfunSat, 09 Dec 2006 02:30:00 GMThttp://www.tkk7.com/errorfun/articles/86511.htmlhttp://www.tkk7.com/errorfun/comments/86511.htmlhttp://www.tkk7.com/errorfun/articles/86511.html#Feedback1http://www.tkk7.com/errorfun/comments/commentRss/86511.htmlhttp://www.tkk7.com/errorfun/services/trackbacks/86511.html转自Q?a >http://bluebug.blog.hexun.com/5930732_d.html

Demo:

package  test;

public   class  StringTest  {
    
/**
     * 
@param  args
     * 
@author  dougq
     
*/

    
public   static   void  main(String[] args) {
        String a 
=   " xyz " ;
        String b
=   " xyz " ;
        System.out.println(a
== b); 

        String a2 
=   new  String( " xyz " );
        String b2
=   new  String( " xyz " );
        System.out.println(a2
== b2); 
    }

}

Result:

true
false

到网上查了好些资料,最l觉得下面这文章是一个最为满意的{复Q全文如下:

全面理解Java中的String数据cd

1. 首先String不属?U基本数据类型,String是一个对象?

  因ؓ对象的默认值是nullQ所以String的默认g是nullQ但它又是一U特D的对象Q有其它对象没有的一些特性?

  2. new String()和new String(“?都是x一个新的空字符Ԍ是空串不是nullQ?

  3. String str=”kvill”;
String str=new String (“kvill?;的区别:

  在这里,我们不谈堆,也不谈栈Q只先简单引入常量池q个单的概念?

  帔R?constant pool)指的是在~译期被定Qƈ被保存在已编译的.class文g中的一些数据。它包括了关于类、方法、接口等中的帔RQ也包括字符串常量?

  看例1Q?


String s0=”kvill?
String s1=”kvill?
String s2=”kv?+ “ill?
System.out.println( s0==s1 );
System.out.println( s0==s2 );


  l果为:


true
true


  首先Q我们要知道Java会确保一个字W串帔R只有一个拷贝?

  因ؓ例子中的s0和s1中的”kvill”都是字W串帔RQ它们在~译期就被确定了Q所以s0==s1为trueQ而”kv”和”ill”也都是字符串常量,当一个字W串由多个字W串帔Rq接而成Ӟ它自p定也是字W串帔RQ所以s2也同样在~译期就被解析ؓ一个字W串帔RQ所以s2也是帔R池中”kvill”的一个引用?

  所以我们得出s0==s1==s2;

  用new String() 创徏的字W串不是帔RQ不能在~译期就定Q所以new String() 创徏的字W串不放入常量池中,它们有自q地址I间?

  看例2Q?


String s0=”kvill?
String s1=new String(”kvill?;
String s2=”kv?+ new String(“ill?;
System.out.println( s0==s1 );
System.out.println( s0==s2 );
System.out.println( s1==s2 );


  l果为:


false
false
false


  ?中s0q是帔R池中”kvill”的应用Qs1因ؓ无法在编译期定Q所以是q行时创建的新对象”kvill”的引用Qs2因ؓ有后半部分new String(“ill?所以也无法在编译期定Q所以也是一个新创徏对象”kvill”的应用;明白了这些也q道ؓ何得出此l果了?

  4. String.intern()Q?

  再补充介l一点:存在?class文g中的帔R池,在运行期被JVM装蝲Qƈ且可以扩充。String的intern()Ҏ是扩充帔R池的一个方法;当一个String实例str调用intern()ҎӞJava查找帔R池中是否有相同Unicode的字W串帔RQ如果有Q则q回其的引用Q如果没有,则在帔R池中增加一个Unicode{于str的字W串q返回它的引用;看例3清楚了

  ?Q?


String s0= “kvill?
String s1=new String(”kvill?;
String s2=new String(“kvill?;
System.out.println( s0==s1 );
System.out.println( ?*********?);
s1.intern();
s2=s2.intern(); //把常量池中“kvill”的引用赋给s2
System.out.println( s0==s1);
System.out.println( s0==s1.intern() );
System.out.println( s0==s2 );


  l果为:


false
**********
false //虽然执行了s1.intern(),但它的返回值没有赋ls1
true //说明s1.intern()q回的是帔R池中”kvill”的引用
true


  最后我再破除一个错误的理解Q?

  有h_“用String.intern()Ҏ则可以将一个Stringcȝ保存C个全局String表中Q如果具有相同值的Unicode字符串已l在q个表中Q那么该Ҏq回表中已有字符串的地址Q如果在表中没有相同值的字符Ԍ则将自己的地址注册到表中“如果我把他说的q个全局的String表理解ؓ帔R池的话,他的最后一句话Q“如果在表中没有相同值的字符Ԍ则将自己的地址注册到表中”是错的Q?

  看例4Q?


String s1=new String(&quot;kvill&quot;);
String s2=s1.intern();
System.out.println( s1==s1.intern() );
System.out.println( s1+&quot; &quot;+s2 );
System.out.println( s2==s1.intern() );


  l果Q?


false
kvill kvill
true


  在这个类中我们没有声名一个”kvill”常量,所以常量池中一开始是没有”kvill”的Q当我们调用s1.intern()后就在常量池中新d了一个”kvill”常量,原来的不在常量池中的”kvill”仍然存在,也就不是“将自己的地址注册到常量池中”了?

  s1==s1.intern()为false说明原来的“kvill”仍然存在;

  s2现在为常量池中“kvill”的地址Q所以有s2==s1.intern()为true?

  5. 关于equals()?=:

  q个对于String单来说就是比较两字符串的Unicode序列是否相当Q如果相{返回true;?=是比较两字符串的地址是否相同Q也是是否是同一个字W串的引用?

  6. 关于String是不可变?/p>

  q一说又要说很多Q大家只要知道String的实例一旦生成就不会再改变了Q比如说QString str=”kv?”ill???”ans?
是?个字W串帔RQ首先”kv”和”ill”生成了”kvill”存在内存中Q然后”kvill”又和??生成 ”kvill “存在内存中Q最后又和生成了”kvill ans?q把q个字符串的地址赋给了str,是因ؓString的“不可变”生了很多临时变量Q这也就是ؓ什么徏议用StringBuffer的原因了Q因为StringBuffer是可改变的?/p>

errorfun 2006-12-09 10:30 发表评论
]]>
վ֩ģ壺 ޹Ʒþ| avһĦ| ĻmvƵ| jjzzjjzz߲| avҹƬƷӰ| ƷƵ| ĻƷþ| ޾Ʒ | ĻƵֻѿ| ޾Ʒ߹ۿ| ձһ| 뾫ƷAVӰ| ëƬѹۿ| һۿ| С˵ͼƬQVOD| ŷ߿ƬAѹۿ| Ʒһѹۿ| ޹Ʒۺɫ | Ʒۺ| ߹ۿ| ҰߵӰۿƵ | ʹA18Ƭ| aëƬѹۿ| gayƬgvվ| þþ뾫Ʒպý | ۺ߳һ| ˳ӰԺ߹ۿ| ŮëƬѲ| ƵƵ| ŷۺһ| ëƬר| ۺҹ| һVR| | ѹۿëƬ| ۲ӰԺѹۿ| ޾Ʒר| Ʒ˿ྫƷþ| AVۺɫһAV | һ| 2019Ļ6|