﻿<?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-狂奔 lion-随笔分类-Java SE</title><link>http://www.blogjava.net/yangyi/category/28784.html</link><description>自强不息</description><language>zh-cn</language><lastBuildDate>Fri, 09 Jul 2010 23:13:50 GMT</lastBuildDate><pubDate>Fri, 09 Jul 2010 23:13:50 GMT</pubDate><ttl>60</ttl><item><title>浅谈Java中的同步的方法和原理</title><link>http://www.blogjava.net/yangyi/archive/2010/07/09/325679.html</link><dc:creator>杨一</dc:creator><author>杨一</author><pubDate>Fri, 09 Jul 2010 11:49:00 GMT</pubDate><guid>http://www.blogjava.net/yangyi/archive/2010/07/09/325679.html</guid><wfw:comment>http://www.blogjava.net/yangyi/comments/325679.html</wfw:comment><comments>http://www.blogjava.net/yangyi/archive/2010/07/09/325679.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yangyi/comments/commentRss/325679.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yangyi/services/trackbacks/325679.html</trackback:ping><description><![CDATA[<p><font style="background-color: #f2f2f2">Java的内存模型中Thread会附有自己的堆栈，寄存器，必要时需要和主存即heap之间同步。<br />
可以使用Synchornized关键字和Concurrent包中的Lock可以保证线程互斥和可见性。</font></p>
<p><font style="background-color: #f2f2f2">互斥性体现在类锁或者对象锁上，每个对象自身都包含一个监视器，该监视器是一个每次只能被一个线程所获取进入的临界区，可以通过wait和notify来退出和准入临界区。可以</font><font style="background-color: #f2f2f2">看出这是一个生产者-消费者的模型。而Concurrent包中的Lock为了能够获得更好的性能和更好的扩展性，以及不依赖于关键字的可读代码，自己实现了这样一个生产消费队列，也</font><font style="background-color: #f2f2f2">就是AbstractQueuedSynchronizer，被称为AQS的机制。每个Lock都内置了一个AbstractQueuedSynchronizer。需要说明的是AbstractQueuedSynchronizer内部实现采用了CAS机制</font><font style="background-color: #f2f2f2">，通过getState, setState, compareAndSetState访问控制一个32bit int的形式进行互斥。</font></p>
<p><font style="background-color: #f2f2f2">那么可见性是如何保证的呢？</font></p>
<p><font style="background-color: #f2f2f2">对于关键字的同步机制，其实可见性就是线程和主存之间的同步时机问题。共有4个时间点需要注意：<br />
1 获取或释放类锁/对象锁的时候。Thread保证reload/flush全部变更<br />
2 volatile就是flush on write或者reload on read<br />
3 当线程首次访问共享变量时，可以得到最新的结果。<br />
题外：所以在构造方法中公布this时很危险的。简单的说，就是构造时不逃脱任何变量，不开启新的线程，只做封装。关于安全构造，请参考<br />
http://www.ibm.com/developerworks/cn/java/j-jtp0618/#resources<br />
4 线程结束时，所有变更会写回主存</font></p>
<p><font style="background-color: #f2f2f2">关于Concurrent Lock如何实现可见性的问题，Doug Lea大侠，只在他的论文中提到，按照JSR133，Unsafe在getState, setState, compareAndSetState时保证了线程的变量的可见</font><font style="background-color: #f2f2f2">性，不需要额外的volatile支持，至于具体这些native做了哪些magic就不得而知了，总之，最后的contract就是保证lock区间的共享变量可见性。开发团队被逼急了就这样回答：<br />
<span style="color: #3366ff"><font style="background-color: #f2f2f2">There seems to be a real reluctance to explain the dirty details. I think the question was definitely understood on the concurrent interest thread, and the </font><font style="background-color: #f2f2f2">answer is that synchronized and concurrent locking are intended to be interchangable in terms of memory semantics when implemented correctly. The answer to </font><font style="background-color: #f2f2f2">matfud's question seems to be "trust us.&#8221;<br />
</font></span></font><font style="background-color: #f2f2f2"><br />
不过这个地方的确是开发团队给我们用户迷惑的地方，在同样应用了CAS机制的Atomic类中，都内嵌了volatile变量，但是再lock块中，他告诉我们可以保证可见性。</font></p>
<p><font style="background-color: #f2f2f2">感兴趣的同学可以下面的两个thread和Doug Lea的thesis：<br />
<a href="http://altair.cs.oswego.edu/pipermail/concurrency-interest/2005-June/001587.html">http://altair.cs.oswego.edu/pipermail/concurrency-interest/2005-June/001587.html</a><br />
<a href="http://forums.sun.com/thread.jspa?threadID=631014&amp;start=15&amp;tstart=0">http://forums.sun.com/thread.jspa?threadID=631014&amp;start=15&amp;tstart=0</a><br />
<a href="http://gee.cs.oswego.edu/dl/papers/aqs.pdf">http://gee.cs.oswego.edu/dl/papers/aqs.pdf</a><br />
</font></p>
<img src ="http://www.blogjava.net/yangyi/aggbug/325679.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yangyi/" target="_blank">杨一</a> 2010-07-09 19:49 <a href="http://www.blogjava.net/yangyi/archive/2010/07/09/325679.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>commons-net FTPClient API存取设计</title><link>http://www.blogjava.net/yangyi/archive/2010/07/07/325504.html</link><dc:creator>杨一</dc:creator><author>杨一</author><pubDate>Wed, 07 Jul 2010 15:08:00 GMT</pubDate><guid>http://www.blogjava.net/yangyi/archive/2010/07/07/325504.html</guid><wfw:comment>http://www.blogjava.net/yangyi/comments/325504.html</wfw:comment><comments>http://www.blogjava.net/yangyi/archive/2010/07/07/325504.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/yangyi/comments/commentRss/325504.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yangyi/services/trackbacks/325504.html</trackback:ping><description><![CDATA[<sub>
<p>文件系统无非就是文件的存取和组织结构。<br />
访问一个文件系统的API也应该是写，读，定位方法（Pathname?/URI?）</p>
<p>FTPClient针对文件的保存和获取各提供了两个方法，分别是：<br />
</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; height: 87px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;storeFile(String&nbsp;remote,&nbsp;InputStream&nbsp;local)<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;OutputStream&nbsp;storeFileStream(String&nbsp;remote)<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;retrieveFile(String&nbsp;remote,&nbsp;OutputStream&nbsp;local)<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;InputStream&nbsp;retrieveFileStream(String&nbsp;remote)<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span></div>
<p>&nbsp;</p>
<p>两个方法貌似相同，实际不同，返回流的那个因为不能马上处理流，所以需要用户手工调用completePendingCommand，而另一个传递流进去的则不需要。可能有同学已经遇到过这个问题了，读写第一个文件时总是正确的，当相同API读写第二个文件时，block住了。这是因为FTPClient要求在进行流操作之后执行completePendingCommand，以确保流处理完毕，因为流处理不是即时的，所以也没有办法不手工调用completePendingCommand。问题是开发者把不返回流的方法末尾加上了completePendingCommand，如果不看代码可能根本不知道。<br />
文档上说：<br />
</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;There&nbsp;are&nbsp;a&nbsp;few&nbsp;FTPClient&nbsp;methods&nbsp;that&nbsp;</span><span style="color: #0000ff">do</span><span style="color: #000000">&nbsp;not&nbsp;complete&nbsp;the<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;entire&nbsp;sequence&nbsp;of&nbsp;FTP&nbsp;commands&nbsp;to&nbsp;complete&nbsp;a&nbsp;transaction.&nbsp;&nbsp;These<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;commands&nbsp;require&nbsp;some&nbsp;action&nbsp;by&nbsp;the&nbsp;programmer&nbsp;after&nbsp;the&nbsp;reception<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;of&nbsp;a&nbsp;positive&nbsp;intermediate&nbsp;command.&nbsp;&nbsp;After&nbsp;the&nbsp;programmer</span><span style="color: #000000">'</span><span style="color: #000000">s&nbsp;code</span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;completes&nbsp;its&nbsp;actions,&nbsp;it&nbsp;must&nbsp;call&nbsp;</span><span style="color: #0000ff">this</span><span style="color: #000000">&nbsp;method&nbsp;to&nbsp;receive<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;the&nbsp;completion&nbsp;reply&nbsp;from&nbsp;the&nbsp;server&nbsp;and&nbsp;verify&nbsp;the&nbsp;success&nbsp;of&nbsp;the<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;entire&nbsp;transaction.</span></div>
<p><br />
但是这样仍然还是让人有点困惑，为什么都是存储/读取的方法，有时候要调用completePendingCommand，有时候不调用？更严重的问题是completePendingCommand调用了getReply，如果一个命令通过socket stream传了过去但是没有getReply，即没有completePendingCommand，那么下次发命令时，将会受到本次返回码的干扰，得到无效的响应。而如果在completePendingCommand之后又进行了一次无辜的completePendingCommand，那么因为FTP Server上没有Reply了，就会block。所以completePendingCommand并不是可以随意添加的。</p>
<p>现在出现了两个问题：<br />
1 completePendingCommand很容易多出来或遗漏<br />
2 显式调用completePendingCommand暴露了底层实现，给用户带来不便，用户只想要InputStream或者OutputStream</p>
<p>为了解决这个问题，可以对InputStream进行扩展，建立一个ReplyOnCloseInputStream，如下：<br />
</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img id="Codehighlighter1_58_285_Open_Image" onclick="this.style.display='none'; Codehighlighter1_58_285_Open_Text.style.display='none'; Codehighlighter1_58_285_Closed_Image.style.display='inline'; Codehighlighter1_58_285_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_58_285_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_58_285_Closed_Text.style.display='none'; Codehighlighter1_58_285_Open_Image.style.display='inline'; Codehighlighter1_58_285_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"  alt="" /><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;ReplyOnCloseInputStream&nbsp;</span><span style="color: #0000ff">extends</span><span style="color: #000000">&nbsp;InputStream</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_58_285_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_58_285_Open_Text"><span style="color: #000000">{<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span style="color: #008000"><br />
<img id="Codehighlighter1_129_143_Open_Image" onclick="this.style.display='none'; Codehighlighter1_129_143_Open_Text.style.display='none'; Codehighlighter1_129_143_Closed_Image.style.display='inline'; Codehighlighter1_129_143_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_129_143_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_129_143_Closed_Text.style.display='none'; Codehighlighter1_129_143_Open_Image.style.display='inline'; Codehighlighter1_129_143_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;ReplyOnCloseInputStream(InputStream&nbsp;is,&nbsp;FTPClient&nbsp;c)</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_129_143_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_129_143_Open_Text"><span style="color: #000000">{<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span style="color: #008000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span style="color: #008000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;@override<br />
<img id="Codehighlighter1_186_283_Open_Image" onclick="this.style.display='none'; Codehighlighter1_186_283_Open_Text.style.display='none'; Codehighlighter1_186_283_Closed_Image.style.display='inline'; Codehighlighter1_186_283_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_186_283_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_186_283_Closed_Text.style.display='none'; Codehighlighter1_186_283_Open_Image.style.display='inline'; Codehighlighter1_186_283_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;close()</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_186_283_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_186_283_Open_Text"><span style="color: #000000">{<br />
<img id="Codehighlighter1_220_244_Open_Image" onclick="this.style.display='none'; Codehighlighter1_220_244_Open_Text.style.display='none'; Codehighlighter1_220_244_Closed_Image.style.display='inline'; Codehighlighter1_220_244_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_220_244_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_220_244_Closed_Text.style.display='none'; Codehighlighter1_220_244_Open_Image.style.display='inline'; Codehighlighter1_220_244_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(c.completePendingCommand)</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_220_244_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_220_244_Open_Text"><span style="color: #000000">{<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;is.close();<br />
<img id="Codehighlighter1_249_279_Open_Image" onclick="this.style.display='none'; Codehighlighter1_249_279_Open_Text.style.display='none'; Codehighlighter1_249_279_Closed_Image.style.display='inline'; Codehighlighter1_249_279_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_249_279_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_249_279_Closed_Text.style.display='none'; Codehighlighter1_249_279_Open_Image.style.display='inline'; Codehighlighter1_249_279_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #0000ff">else</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_249_279_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_249_279_Open_Text"><span style="color: #000000">{<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">throw&nbsp;Exception</span><span style="color: #008000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span><span style="color: #000000">&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #008000">//</span><span style="color: #008000"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span style="color: #008000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;ReplyOnCloseInputStream(is,&nbsp;client);</span></div>
<p><br />
这样封装之后，FTPClient的用户只需要正常在处理完流之后关闭即可，而不必暴露实现细节。保存文件也可以用相同的方法封装OutputStream。</p>
</sub>
<img src ="http://www.blogjava.net/yangyi/aggbug/325504.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yangyi/" target="_blank">杨一</a> 2010-07-07 23:08 <a href="http://www.blogjava.net/yangyi/archive/2010/07/07/325504.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于ThreadLocal的内存泄露</title><link>http://www.blogjava.net/yangyi/archive/2010/07/02/325100.html</link><dc:creator>杨一</dc:creator><author>杨一</author><pubDate>Fri, 02 Jul 2010 10:27:00 GMT</pubDate><guid>http://www.blogjava.net/yangyi/archive/2010/07/02/325100.html</guid><wfw:comment>http://www.blogjava.net/yangyi/comments/325100.html</wfw:comment><comments>http://www.blogjava.net/yangyi/archive/2010/07/02/325100.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/yangyi/comments/commentRss/325100.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yangyi/services/trackbacks/325100.html</trackback:ping><description><![CDATA[ThreadLocal是一种confinement，confinement和local及immutable都是线程安全的（如果JVM可信的话）。因为对每个线程和value之间存在hash表，而线程数量未知，从表象来看ThreadLocal会存在内存泄露，读了代码，发现实际上也可能会内存泄露。<br />
<br />
事实上每个Thread实例都具备一个ThreadLocal的map，以ThreadLocal Instance为key，以绑定的Object为Value。而这个map不是普通的map，它是在ThreadLocal中定义的，它和普通map的最大区别就是它的Entry是针对ThreadLocal弱引用的，即当外部ThreadLocal引用为空时，map就可以把ThreadLocal交给GC回收，从而得到一个null的key。<br />
<br />
这个threadlocal内部的map在Thread实例内部维护了ThreadLocal Instance和bind value之间的关系，这个map有threshold，当超过threshold时，map会首先检查内部的ThreadLocal（前文说过，map是弱引用可以释放）是否为null，如果存在null，那么释放引用给gc，这样保留了位置给新的线程。如果不存在slate threadlocal，那么double threshold。除此之外，还有两个机会释放掉已经废弃的threadlocal占用的内存，一是当hash算法得到的table index刚好是一个null key的threadlocal时，直接用新的threadlocal替换掉已经废弃的。另外每次在map中新建一个entry时（即没有和用过的或未清理的entry命中时），会调用cleanSomeSlots来遍历清理空间。此外，当Thread本身销毁时，这个map也一定被销毁了（map在Thread之内），这样内部所有绑定到该线程的ThreadLocal的Object Value因为没有引用继续保持，所以被销毁。<br />
<br />
从上可以看出Java已经充分考虑了时间和空间的权衡，但是因为置为null的threadlocal对应的Object Value无法及时回收。map只有到达threshold时或添加entry时才做检查，不似gc是定时检查，不过我们可以手工轮询检查，显式调用map的remove方法，及时的清理废弃的threadlocal内存。需要说明的是，只要不往不用的threadlocal中放入大量数据，问题不大，毕竟还有回收的机制。<br />
<br />
综上，废弃threadlocal占用的内存会在3中情况下清理：<br />
1 thread结束，那么与之相关的threadlocal value会被清理<br />
2 GC后，thread.threadlocals(map) threshold超过最大值时，会清理<br />
3 GC后，thread.threadlocals(map) 添加新的Entry时，hash算法没有命中既有Entry时，会清理<br />
<br />
那么何时会&#8220;内存泄露&#8221;?当Thread长时间不结束，存在大量废弃的ThreadLocal，而又不再添加新的ThreadLocal（或新添加的ThreadLocal恰好和一个废弃ThreadLocal在map中命中）时。
<img src ="http://www.blogjava.net/yangyi/aggbug/325100.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yangyi/" target="_blank">杨一</a> 2010-07-02 18:27 <a href="http://www.blogjava.net/yangyi/archive/2010/07/02/325100.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>NIO学习之Web服务器示例</title><link>http://www.blogjava.net/yangyi/archive/2010/06/25/324501.html</link><dc:creator>杨一</dc:creator><author>杨一</author><pubDate>Fri, 25 Jun 2010 11:19:00 GMT</pubDate><guid>http://www.blogjava.net/yangyi/archive/2010/06/25/324501.html</guid><wfw:comment>http://www.blogjava.net/yangyi/comments/324501.html</wfw:comment><comments>http://www.blogjava.net/yangyi/archive/2010/06/25/324501.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yangyi/comments/commentRss/324501.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yangyi/services/trackbacks/324501.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1 根据cpu core数量确定selector数量 2 用一个selector服务accept，其他selector按照core-1分配线程数运行 3 accept selector作为生产者把获得的请求放入队列 4 某个selector作为消费者从blocking queue中取出请求socket channel，并向自己注册 5 当获得read信号时，selector建立工作...&nbsp;&nbsp;<a href='http://www.blogjava.net/yangyi/archive/2010/06/25/324501.html'>阅读全文</a><img src ="http://www.blogjava.net/yangyi/aggbug/324501.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yangyi/" target="_blank">杨一</a> 2010-06-25 19:19 <a href="http://www.blogjava.net/yangyi/archive/2010/06/25/324501.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅谈Java中的通信机制及与C/C++ API的集成（下）</title><link>http://www.blogjava.net/yangyi/archive/2007/12/06/165761.html</link><dc:creator>杨一</dc:creator><author>杨一</author><pubDate>Thu, 06 Dec 2007 04:19:00 GMT</pubDate><guid>http://www.blogjava.net/yangyi/archive/2007/12/06/165761.html</guid><wfw:comment>http://www.blogjava.net/yangyi/comments/165761.html</wfw:comment><comments>http://www.blogjava.net/yangyi/archive/2007/12/06/165761.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/yangyi/comments/commentRss/165761.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yangyi/services/trackbacks/165761.html</trackback:ping><description><![CDATA[接着上次的话题，今天我们聊聊gSOAP这个框架，我们把用C写的旧有系统用gSOAP改造一下，通过SOA的形式发布出去。<br />
上文提到，利用gSOAP可以做到以下3点：<br />
1 一个Stand-alone的服务器外壳<br />
2 一个根据API程序自动生成的Web Services服务<br />
3 一个WSDL描述符文件<br />
<br />
客户根据 WSDL 描述文档，会生成一个 SOAP 请求消息。Web Services 都是放在Web服务器后面，客户生成的SOAP请求会被嵌入在一个HTTP POST请求中，发送到 Web 服务器来。Web 服务器再把这些请求转发给 Web Services 请求处理器。请求处理器的作用在于，解析收到的 SOAP 请求，调用 Web Services，然后再生成相应的 SOAP 应答。Web 服务器得到 SOAP 应答后，会再通过 HTTP应答的方式把信息送回到客户端。<br />
WSDL是Web服务中客户端和服务端沟通的桥梁，描述了对象提供的方法。SOAP帮我们制定了一份被官方认可的对象的封装方法。有了WSDL，客户端只关心如何把参数用Soap封装起来发出去，并获取结果。服务端只关心如何对Soap进行拆包-&gt;服务-&gt;封包。gSOAP可以帮我们实现上述过程中的拆包和封包，而我们可以只关心服务的实现。<br />
<br />
言归正传，在这里我们以一个简单的实现加、减、开放的Web Services的服务为例子，介绍gSOAP的使用：<br />
为了发布这个Web服务，首先我们需要把服务的接口定义好，这个服务可能是一个现有服务的Adapter，为此我们定义头文件<br />
calc.h:<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">typedef&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;xsd__double;<br />
</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;ns__add(xsd__double&nbsp;a,&nbsp;xsd__double&nbsp;b,&nbsp;xsd__double&nbsp;</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">result);<br />
</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;ns__sub(xsd__double&nbsp;a,&nbsp;xsd__double&nbsp;b,&nbsp;xsd__double&nbsp;</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">result);<br />
</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;ns__sqrt(xsd__double&nbsp;a,&nbsp;xsd__double&nbsp;</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">result);&nbsp;</span></div>
注意到这里面我们把double定义成了xsd__double（两个下划线），这是为了告诉gSOAP，我们需要的soap格式和WSDL格式是基于Document/literal的而非rpc/encoded.为了不把事情搞复杂，在这里我只能说，Java1.6自带的Web Services工具只支持Document/literal格式的WSDL，所以我们生成这种格式的WSDL。至于这两种格式之间选择和他们的long story，大家可以参考下面的文章：<br />
http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/<br />
编写好头文件后，我们就可以利用gSOAP提供的工具进行生成了：<br />
/usr/lib/gsoap-2.7/bin/soapcpp2 -S -2 calc.h<br />
生成的主要文件详见附件。<br />
下面我们实现calc.h中定义的函数：<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;Contents&nbsp;of&nbsp;file&nbsp;"calc.cpp":&nbsp;</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">#include&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">soapH.h</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">&nbsp;<br />
#include&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">ns.nsmap</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">&nbsp;<br />
#include&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">math.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;<br />
</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;main()<br />
{<br />
&nbsp;&nbsp;&nbsp;struct&nbsp;soap&nbsp;soap;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;m,&nbsp;s;&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;master&nbsp;and&nbsp;slave&nbsp;sockets</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;soap_init(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">soap);<br />
&nbsp;&nbsp;&nbsp;m&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;soap_bind(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">soap,&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">localhost</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">9999</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">100</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;(m&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">soap,&nbsp;stderr);<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Socket&nbsp;connection&nbsp;successful:&nbsp;master&nbsp;socket&nbsp;=&nbsp;%d\n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,&nbsp;m);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);">&nbsp;(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;i&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">;&nbsp;;&nbsp;i</span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;soap_accept(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">soap);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;(s&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">soap,&nbsp;stderr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">%d:&nbsp;accepted&nbsp;connection&nbsp;from&nbsp;IP=%d.%d.%d.%d&nbsp;socket=%d</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,&nbsp;i,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(soap.ip&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">24</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">0xFF</span><span style="color: rgb(0, 0, 0);">,&nbsp;(soap.ip&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">16</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">0xFF</span><span style="color: rgb(0, 0, 0);">,&nbsp;(soap.ip&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">8</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">0xFF</span><span style="color: rgb(0, 0, 0);">,&nbsp;soap.ip</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">0xFF</span><span style="color: rgb(0, 0, 0);">,&nbsp;s);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;(soap_serve(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">soap)&nbsp;</span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);">&nbsp;SOAP_OK)&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;process&nbsp;RPC&nbsp;request</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_print_fault(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">soap,&nbsp;stderr);&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;print&nbsp;error</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">request&nbsp;served\n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_destroy(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">soap);&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;clean&nbsp;up&nbsp;class&nbsp;instances</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soap_end(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">soap);&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;clean&nbsp;up&nbsp;everything&nbsp;and&nbsp;close&nbsp;socket</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;soap_done(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">soap);&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;close&nbsp;master&nbsp;socket&nbsp;and&nbsp;detach&nbsp;environment</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">}<br />
</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;Implementation&nbsp;of&nbsp;the&nbsp;"add"&nbsp;remote&nbsp;method:&nbsp;</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;ns__add(struct&nbsp;soap&nbsp;</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">soap,&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;a,&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;b,&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">result)&nbsp;<br />
{&nbsp;<br />
&nbsp;&nbsp;&nbsp;result&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;a&nbsp;</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;b;&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;SOAP_OK;&nbsp;<br />
}&nbsp;<br />
</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;Implementation&nbsp;of&nbsp;the&nbsp;"sub"&nbsp;remote&nbsp;method:&nbsp;</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;ns__sub(struct&nbsp;soap&nbsp;</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">soap,&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;a,&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;b,&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">result)&nbsp;<br />
{&nbsp;<br />
&nbsp;&nbsp;&nbsp;result&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;a&nbsp;</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">&nbsp;b;&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;SOAP_OK;&nbsp;<br />
}&nbsp;<br />
</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;Implementation&nbsp;of&nbsp;the&nbsp;"sqrt"&nbsp;remote&nbsp;method:&nbsp;</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;ns__sqrt(struct&nbsp;soap&nbsp;</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">soap,&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;a,&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">result)&nbsp;<br />
{&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;(a&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">)&nbsp;<br />
&nbsp;&nbsp;&nbsp;{&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;sqrt(a);&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;SOAP_OK;&nbsp;<br />
&nbsp;&nbsp;&nbsp;}&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;{&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;soap_sender_fault(soap,&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Square&nbsp;root&nbsp;of&nbsp;negative&nbsp;value</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">I&nbsp;can&nbsp;only&nbsp;compute&nbsp;the&nbsp;square&nbsp;root&nbsp;of&nbsp;a&nbsp;non-negative&nbsp;value</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;&nbsp;}&nbsp;<br />
}&nbsp;</span></div>
前文提到过，我们不希望为了发布基于Web Services的C语言的API而开发或应用一个大的Web服务器。我们代码中的main函数实现了一个最简单的Web Server（基于Socket）.这个Server利用gSOAP生成的API来提供针对SOAP的处理。<br />
下面我们把这个嵌入式的web server编译，编译的时候注意stdsoap2.cpp这个文件是从gSOAP包中拷贝而来，不是自动生成的，大家下载gSOAP后直接就能找到这个文件及其头文件。<br />
g++ -o calcServer calc.cpp soapC.cpp soapServer.cpp stdsoap2.cpp<br />
一个以Web Servers形式提供的C API诞生了。<br />
在server端执行./calcServer<br />
<br />
下面讨论如何用Java1.6的自带工具生成一个客户端stub:<br />
把gSOAP生成的WSDL拷贝到我们的Java开发环境中来，按照Web Services Server中定义的端口和服务器，配置参数生成客户端Web Services代码：<br />
/usr/lib/jvm/jdk1.6.0_03/bin/wsimport -extension -httpproxy:localhost:9999 -verbose ns.wsdl<br />
<br />
生成后，把这个环境添加到eclipse的编译环境中来，然后在eclipse中建一个新的类：<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;Test&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;main(String&nbsp;args[])&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Service&nbsp;service&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Service();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;h&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;service.getService().sub(</span><span style="color: rgb(0, 0, 0);">20000</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(h);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
运行后得到结果19999.0<br />
<br />
总结：当集成Java和C两种平台时，我们可以有多种解决方案，但首先我们应该想到gSOAP因为它能够很出色地完成任务。<br />
文中相关代码：<br />
<a title="http://www.blogjava.net/Files/yangyi/gsoap.zip" href="/Files/yangyi/gsoap.zip">http://www.blogjava.net/Files/yangyi/gsoap.zip</a><br />
广告：本人明年毕业，正在找工作，个人简历：<br />
<a title="个人中英文简历" href="/Files/yangyi/My%20Resume.zip">http://www.blogjava.net/Files/yangyi/My%20Resume.zip</a><br />
<img src ="http://www.blogjava.net/yangyi/aggbug/165761.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yangyi/" target="_blank">杨一</a> 2007-12-06 12:19 <a href="http://www.blogjava.net/yangyi/archive/2007/12/06/165761.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅谈Java中的通信机制及与C/C++ API的集成（上）</title><link>http://www.blogjava.net/yangyi/archive/2007/12/04/165241.html</link><dc:creator>杨一</dc:creator><author>杨一</author><pubDate>Tue, 04 Dec 2007 09:33:00 GMT</pubDate><guid>http://www.blogjava.net/yangyi/archive/2007/12/04/165241.html</guid><wfw:comment>http://www.blogjava.net/yangyi/comments/165241.html</wfw:comment><comments>http://www.blogjava.net/yangyi/archive/2007/12/04/165241.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yangyi/comments/commentRss/165241.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yangyi/services/trackbacks/165241.html</trackback:ping><description><![CDATA[背景：<br />
对于旧有系统的改造和升级，最苦恼的莫过于跨平台，跨语言。我的一个朋友最近从Java专向了专攻.NET——因为.NET的CLR既有类似Java虚拟机概念这种已经被证明很成功的底层托管能力。又对于Windows的就有桌面应用提供了良好的兼容。<br />
最近我的一个个人项目也面临着这样的需求。一个C语言开发的中间件，通过API暴露给二次开发及插件应用。现在由于对其应用的需求变得日趋复杂，而且正在脱离Unix的管理环境，走向基于JWS这样的BCS管理。有朋友推荐我用JNI，但这样一是增加了耦合度，二是让Java睡在JNI感觉不太安稳。在认知了上下两层的系统平台后，问题变得明朗起来：如何在HTTP协议下实现Java和C之间的交互？<br />
思路：<br />
本人对Java比较熟悉，先从Java的角度入手，Java间的通信方法：<br />
1 通过URL，Applet/JWS访问被影射到URL的动态资源（Servlet）<br />
2 通过URL，Applet/JWS访问共享的静态资源（Server定期更新静态资源）<br />
3 通过序列化和反序列化，实现简单对象的传输（比如Resin的Hessian框架就提供了这种通信的方式）<br />
4 通过一些工具做代码生成，利用Web Services实现客户端和服务端的交互<br />
此外脱离HTTP，还可以做RMI，socket编程<br />
<br />
现在问题是通信的一端由Java变成了C/C++, 于是， 解决方案1需要把动态资源由CGI来定义，而方案3变得不再适用。于是方案有：<br />
1 通过URL，Applet/JWS访问被影射到URL的动态资源（CGI）<br />
2 通过URL，Applet/JWS访问共享的静态资源（Server定期更新静态资源）<br />
3 通过一些工具做代码生成，利用Web Services实现客户端和服务端的交互（&#215;&#215;&#215;这是我们讨论的重点&#215;&#215;&#215;）<br />
<br />
解决方案:<br />
现在针对上文提出的3中通信方式中的1和3谈一谈实现的方法，2的实现方案比较灵活，需要发挥大家的想象力了：）<br />
针对CGI：<br />
首先CGI可以配置在各种主流的服务器中作为后端的脚本运行。大家可能对Servlet更熟悉一些。<br />
CGI可以用脚本写，也可以用C来实现。CGI被触发后，通过系统的环境变量来获得输入，在处理完毕后向标准输出中输出结果。<br />
由此可以想见，Web服务器在接受到来自HTTP协议的请求后，首先把请求的参数获取到，然后设置到环境变量里。<br />
根据对访问的URL的解析和服务器自身的配置，找到服务于请求的CGI程序的位置，然后执行这个程序。<br />
这个程序被执行后通过环境变量得到了服务器先前设置在环境变量中的参数。在经过一些复杂的逻辑操作后，向标准输出输出结果。<br />
这个输出又被Web服务器所捕获，转而传递回请求的客户端。<br />
更多关于CGI的知识和理解，大家可以通过google来寻找答案<br />
<br />
上述CGI的方式可以让我们直接获取到结果，但是方案比较原始和基础。其缺点有：<br />
1 需要自己制定类型传输协议，做封装和拆封，否则只支持字符串<br />
2 我们不会为了要用C的API就给它装一个或者自己实现一个Web服务器的，这让我们的底层程序显得蠢笨而冗余。我们希望能有一个超薄的Server外壳，<br />
在对API封装后，通过某个端口进行开放即可。<br />
<br />
针对Web Servcies：<br />
Based on上面的两个不足，我们只能把希望寄托在Web Services身上了，<br />
笔者在这里推荐给大家的是在C/C++很著名的Web Services工具gSOAP。大家可以到http://gsoap2.sourceforge.net/上去下载这个工具。<br />
通过这个工具，我们可以做到：<br />
1 一个Stand-alone的服务器外壳<br />
2 一个根据API程序自动生成的Web Services服务<br />
3 一个WSDL描述符文件<br />
<br />
有关基于gSOAP的Web Services C服务端和Java客户端的运行机理，及通过Java客户端访问gSOAP的Web Services的过程中需要注意的问题（笔者费了一天周折才搞清楚），将在下一篇中描述<br />
<br />
广告时间：<br />
本人是哈工大的研究生，明年7月毕业。正在找工作，如果有工作机会，别忘了通知小弟哦（contactyang@163.com） 
<img src ="http://www.blogjava.net/yangyi/aggbug/165241.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yangyi/" target="_blank">杨一</a> 2007-12-04 17:33 <a href="http://www.blogjava.net/yangyi/archive/2007/12/04/165241.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>值得借鉴的SWT shell构造方法的编程模式</title><link>http://www.blogjava.net/yangyi/archive/2006/09/10/68802.html</link><dc:creator>杨一</dc:creator><author>杨一</author><pubDate>Sun, 10 Sep 2006 06:00:00 GMT</pubDate><guid>http://www.blogjava.net/yangyi/archive/2006/09/10/68802.html</guid><wfw:comment>http://www.blogjava.net/yangyi/comments/68802.html</wfw:comment><comments>http://www.blogjava.net/yangyi/archive/2006/09/10/68802.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yangyi/comments/commentRss/68802.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yangyi/services/trackbacks/68802.html</trackback:ping><description><![CDATA[SWT shell的构造方法<a></a>影响深远，是值得我们借鉴的编程模式，采用了如下的形式: <br />
<font size="5"><font color="#ff3300">
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;MyClass(MyClass.A&nbsp;</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">&nbsp;MyClass.B&nbsp;</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">&nbsp;MyClass.C)</span></div>
</font></font>其中，对于MyClass.A定义为 1&lt;&lt;1，MyClass.B 定义为 1&lt;&lt;2 以此类推。<br />
在我们都知道，在java中整形是4个字节，那么除去符号位，还可以有31bit用来加入各种各样的开关，<br />
当31个条件都满足时，将得到Integer.MAX_VALUE.这样保证了传入的是一个整型的数，而在构造方法内部可以这样判断：<br />
<br />
<font color="#990000" size="5">
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;MyClass(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;types){<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(types&nbsp;</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">&nbsp;MyClass.A&nbsp;</span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">表示在A条件被设定时的情况</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/images/dot.gif"  alt="" /><br />
&nbsp;&nbsp;}<br />
}</span></div>
</font><br />
这种模式主要用来配置当一个类中的多个属性都是&#8220;开关型&#8221;的变量 —— 即位布尔型时的情况，从用<br />
<br />
户接口的角度，增加了利用接口开发程序人员所编写程序的可读性，因此当所编写的程序仅供自己使用<br />
<br />
时，我个人不推荐这种方法；而对于相反的情况，则强烈推荐。另一方面来说，这种编程模式提高了程<br />
<br />
序的运行效率。<iframe src="http://www.google.com/gn/static_files/blank.html" style="position: absolute; display: block; opacity: 0.7; z-index: 500; width: 19px; height: 22px; top: 316px; right: 576px;" id="gn_notemagic" frameborder="0"></iframe> 
<img src ="http://www.blogjava.net/yangyi/aggbug/68802.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yangyi/" target="_blank">杨一</a> 2006-09-10 14:00 <a href="http://www.blogjava.net/yangyi/archive/2006/09/10/68802.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何用java做数组乱序？</title><link>http://www.blogjava.net/yangyi/archive/2006/08/20/64598.html</link><dc:creator>杨一</dc:creator><author>杨一</author><pubDate>Sun, 20 Aug 2006 03:58:00 GMT</pubDate><guid>http://www.blogjava.net/yangyi/archive/2006/08/20/64598.html</guid><wfw:comment>http://www.blogjava.net/yangyi/comments/64598.html</wfw:comment><comments>http://www.blogjava.net/yangyi/archive/2006/08/20/64598.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/yangyi/comments/commentRss/64598.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yangyi/services/trackbacks/64598.html</trackback:ping><description><![CDATA[用java做了一个数组乱序，首先建立快速排序算法，排序的依据是根据序列中随机产生的序列号，序列号利用map保证在每次排序过程中只产生一次，不知道有没有效率更高的方法，大家咚咚脑筋哈<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;randomList(List&nbsp;list)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collections.sort(list,&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Comparator(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HashMap&nbsp;map&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;HashMap();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;compare(Object&nbsp;v1,&nbsp;Object&nbsp;v2)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;init(v1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;init(v2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;n1&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;((Double)map.get(v1)).doubleValue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">double</span><span style="color: rgb(0, 0, 0);">&nbsp;n2&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;((Double)map.get(v2)).doubleValue();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(n1&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;n2)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(n1&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">&nbsp;n2)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;init(Object&nbsp;v){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(map.get(v)&nbsp;</span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map.put(v,&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Double(Math.random()));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">protected</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;finalize()&nbsp;</span><span style="color: rgb(0, 0, 255);">throws</span><span style="color: rgb(0, 0, 0);">&nbsp;Throwable&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<img src ="http://www.blogjava.net/yangyi/aggbug/64598.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yangyi/" target="_blank">杨一</a> 2006-08-20 11:58 <a href="http://www.blogjava.net/yangyi/archive/2006/08/20/64598.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于eclipse插件配置</title><link>http://www.blogjava.net/yangyi/archive/2006/07/11/57705.html</link><dc:creator>杨一</dc:creator><author>杨一</author><pubDate>Tue, 11 Jul 2006 12:00:00 GMT</pubDate><guid>http://www.blogjava.net/yangyi/archive/2006/07/11/57705.html</guid><wfw:comment>http://www.blogjava.net/yangyi/comments/57705.html</wfw:comment><comments>http://www.blogjava.net/yangyi/archive/2006/07/11/57705.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/yangyi/comments/commentRss/57705.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yangyi/services/trackbacks/57705.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; eclipse很麻烦的一点就是eclipse的频繁升级+IT技术人员追求最先进的技术+eclipse平台对插件不保证向下兼容，先在eclipse的官方网站http://www.eclipse.org提供了一个一站式服务的好办法，就是Callisto,这里面集成了图形设计器,WTP等大多数能想象到的功能,免去了我们诸多麻烦.3.2以后的eclipse必将更加美好!<br />
<br />
<span style="text-decoration: underline;"><br />
</span><a href="http://www.eclipse.org/callisto" target="_blank"></a> 
<img src ="http://www.blogjava.net/yangyi/aggbug/57705.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yangyi/" target="_blank">杨一</a> 2006-07-11 20:00 <a href="http://www.blogjava.net/yangyi/archive/2006/07/11/57705.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>