﻿<?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-yeshucheng-随笔分类-java基础</title><link>http://www.blogjava.net/yeshucheng/category/34002.html</link><description>追逐自己，追逐方向，心随悟所动</description><language>zh-cn</language><lastBuildDate>Sun, 12 Dec 2010 13:43:20 GMT</lastBuildDate><pubDate>Sun, 12 Dec 2010 13:43:20 GMT</pubDate><ttl>60</ttl><item><title>Future结合ExecutorService的简单实例</title><link>http://www.blogjava.net/yeshucheng/archive/2010/12/12/340393.html</link><dc:creator>叶澍成</dc:creator><author>叶澍成</author><pubDate>Sun, 12 Dec 2010 06:44:00 GMT</pubDate><guid>http://www.blogjava.net/yeshucheng/archive/2010/12/12/340393.html</guid><description><![CDATA[<p>//ValueObject类</p>
<p>
<div style="background-color: #eeeeee; font-size: 13px; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;AdEntity&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;String&nbsp;id;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;String&nbsp;name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;String&nbsp;broker;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;String&nbsp;date;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;String&nbsp;body;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">get/set<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;String&nbsp;toString(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">【编号为:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">+</span><span style="color: #000000; ">id</span><span style="color: #000000; ">+</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,广告名称为:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">+</span><span style="color: #000000; ">name</span><span style="color: #000000; ">+</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,代理商为:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">+</span><span style="color: #000000; ">broker</span><span style="color: #000000; ">+</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,发布日期为:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">+</span><span style="color: #000000; ">date</span><span style="color: #000000; ">+</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,内容为:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">+</span><span style="color: #000000; ">body</span><span style="color: #000000; ">+</span><span style="color: #000000; ">"</span><span style="color: #000000; ">】</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
</p>
<p>//调用任务类</p>
<p>
<div style="background-color: #eeeeee; font-size: 13px; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;AdTask&nbsp;</span><span style="color: #0000FF; ">implements</span><span style="color: #000000; ">&nbsp;Callable</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">AdEntity</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;AdEntity&nbsp;call()&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;Exception&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;模拟远程调用花费的一些时间</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(</span><span style="color: #000000; ">5</span><span style="color: #000000; ">*</span><span style="color: #000000; ">1000</span><span style="color: #000000; ">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AdEntity&nbsp;vo</span><span style="color: #000000; ">=</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;AdEntity();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vo.setId(String.valueOf(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Random().nextInt(</span><span style="color: #000000; ">1000</span><span style="color: #000000; ">)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vo.setName(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Ad@内衣广告</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vo.setBroker(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">CHANNEL</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Date&nbsp;date</span><span style="color: #000000; ">=</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Date();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SimpleDateFormat&nbsp;sdf</span><span style="color: #000000; ">=</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;SimpleDateFormat(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">yyyy-MM-dd</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;dateStr</span><span style="color: #000000; ">=</span><span style="color: #000000; ">sdf.format(date);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vo.setDate(dateStr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vo.setBody(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">远端内容</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;vo;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</span></div>
</p>
<p>//主函数</p>
<p>
<div style="background-color: #eeeeee; font-size: 13px; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;TestQueryMemg&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080; ">@param</span><span style="color: #008000; ">&nbsp;args<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080; ">@throws</span><span style="color: #008000; ">&nbsp;ExecutionException&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080; ">@throws</span><span style="color: #008000; ">&nbsp;InterruptedException&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main(String[]&nbsp;args)&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;InterruptedException,&nbsp;ExecutionException&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExecutorService&nbsp;exec</span><span style="color: #000000; ">=</span><span style="color: #000000; ">Executors.newCachedThreadPool();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">创建Future来完成网络调用任务</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Callable</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">AdEntity</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;returnAd</span><span style="color: #000000; ">=</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;AdTask();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Future</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">AdEntity</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;future</span><span style="color: #000000; ">=</span><span style="color: #000000; ">exec.submit(returnAd);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">开始执行本地化查询信息</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AdEntity&nbsp;localAd</span><span style="color: #000000; ">=</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;AdEntity();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localAd.setId(String.valueOf(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Random().nextInt(</span><span style="color: #000000; ">1000</span><span style="color: #000000; ">)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localAd.setName(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Ad@食品广告</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localAd.setBroker(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">蒙牛</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SimpleDateFormat&nbsp;sdf</span><span style="color: #000000; ">=</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;SimpleDateFormat(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">yyyy-MM-dd</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;dateStr</span><span style="color: #000000; ">=</span><span style="color: #000000; ">sdf.format(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Date());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localAd.setDate(dateStr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localAd.setBody(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">内容本地</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">当前本地化查询内容为：</span><span style="color: #000000; ">"</span><span style="color: #000000; ">+</span><span style="color: #000000; ">localAd.toString());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">稍等片刻以获取远端信息<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">(</span><span style="color: #000000; ">!</span><span style="color: #000000; ">future.isDone()){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">try</span><span style="color: #000000; ">&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(</span><span style="color: #000000; ">1</span><span style="color: #000000; ">*</span><span style="color: #000000; ">1000</span><span style="color: #000000; ">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">catch</span><span style="color: #000000; ">&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<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;&nbsp;&nbsp;&nbsp;&nbsp;AdEntity&nbsp;entityRemote</span><span style="color: #000000; ">=</span><span style="color: #000000; ">(AdEntity)future.get();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">合并查询内容为：\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">+</span><span style="color: #000000; ">localAd.toString()</span><span style="color: #000000; ">+</span><span style="color: #000000; ">"</span><span style="color: #000000; ">\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">+</span><span style="color: #000000; ">entityRemote.toString());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
</p>
<div><br />
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/yeshucheng/aggbug/340393.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yeshucheng/" target="_blank">叶澍成</a> 2010-12-12 14:44 <a href="http://www.blogjava.net/yeshucheng/archive/2010/12/12/340393.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程方法基础理解</title><link>http://www.blogjava.net/yeshucheng/archive/2009/07/20/287407.html</link><dc:creator>叶澍成</dc:creator><author>叶澍成</author><pubDate>Mon, 20 Jul 2009 02:00:00 GMT</pubDate><guid>http://www.blogjava.net/yeshucheng/archive/2009/07/20/287407.html</guid><wfw:comment>http://www.blogjava.net/yeshucheng/comments/287407.html</wfw:comment><comments>http://www.blogjava.net/yeshucheng/archive/2009/07/20/287407.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yeshucheng/comments/commentRss/287407.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yeshucheng/services/trackbacks/287407.html</trackback:ping><description><![CDATA[&nbsp;
<p><span style="color: black; font-family: 宋体">线程，是指正在执行的一个指点令序列。在</span><span style="color: black; font-family: Verdana">java</span><span style="color: black; font-family: 宋体">平台上是指从一个线程对象的</span><span style="color: black; font-family: Verdana">start()</span><span style="color: black; font-family: 宋体">开始。运行</span><span style="color: black; font-family: Verdana">run</span><span style="color: black; font-family: 宋体">方法体中的那一段相对独立的过程。</span></p>
<h2><span style="font-family: 黑体">线程的并发与并行</span></h2>
<p style="margin-left: 21pt; text-indent: 21pt"><span style="font-family: 宋体">在过去的电脑都已单</span>CPU<span style="font-family: 宋体">作为主要的处理方式，无论是</span>PC<span style="font-family: 宋体">或者是服务器都是如此。系统调用某一个时刻只能有一个线程运行。当然这当中采用了比较多的策略来做时间片轮询。通过不断的调度切换来运行线程运行，而这种方式就叫做并发（</span><span style="font-size: 9pt; color: black; font-family: Verdana">concurrent</span><span style="font-family: 宋体">）。</span></p>
<p style="margin-left: 21pt"><span style="font-family: 宋体">随着工艺水平的逐渐提升，</span>CPU<span style="font-family: 宋体">的技术也在不断增进。因此在如今多个</span>CPU<span style="font-family: 宋体">已经不是什么特别的，而大家常常以</span>SMP<span style="font-family: 宋体">的方式来形容多个</span>CPU<span style="font-family: 宋体">来处理两个或者两个以上的线程运行方式就称为并行（</span><span style="font-size: 9pt; color: black; font-family: Verdana">parallel</span><span style="font-family: 宋体">）。</span></p>
<h2>JAVA<span style="font-family: 黑体">线程对象</span></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">继承</span>Thread<span style="font-family: 宋体">，实现</span>start()<span style="font-family: 宋体">方法</span></p>
<p style="margin-left: 21pt"><span style="font-family: 宋体">要实现线程运行，</span>JAVA<span style="font-family: 宋体">中有两种方式：</span></p>
<p style="margin-left: 21pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">实现</span>Runnable<span style="font-family: 宋体">，然后再传递给</span>Thread<span style="font-family: 宋体">实例</span></p>
<p style="margin-left: 21pt"><span style="font-family: 宋体">注意：线程对象和线程是两个截然不同的概念。</span></p>
<p style="margin-left: 21pt"><strong><em><span style="font-family: 宋体">线程对象</span></em></strong><strong><em><span style="color: black; font-family: 宋体">是</span></em></strong><strong><em><span style="color: black; font-family: Verdana">JVM</span></em></strong><strong><em><span style="color: black; font-family: 宋体">产生的一个普通的</span></em></strong><strong><em><span style="color: black; font-family: Verdana">Object</span></em></strong><strong><em><span style="color: black; font-family: 宋体">子类</span></em></strong></p>
<p style="margin-left: 21pt"><strong><em><span style="color: black; font-family: 宋体">线程是</span></em></strong><strong><em><span style="color: black; font-family: Verdana">CPU</span></em></strong><strong><em><span style="color: black; font-family: 宋体">分配给这个对象的一个运行过程</span></em></strong></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; font-family: Verdana">public class Test {</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; font-family: Verdana">&nbsp;public static void main(String[] args) throws Exception{</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; font-family: Verdana">&nbsp;&nbsp;&nbsp; MyThread mt = new MyThread();</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; font-family: Verdana">&nbsp;&nbsp;&nbsp; mt.start();</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; font-family: Verdana">&nbsp;&nbsp;&nbsp; mt.join();</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; font-family: Verdana">&nbsp;&nbsp;&nbsp; Thread.sleep(3000);</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; font-family: Verdana">&nbsp;&nbsp;&nbsp; mt.start();</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; font-family: Verdana">&nbsp;}</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; font-family: Verdana">}</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; font-family: 宋体">当线程对象</span><span style="font-size: 9pt; font-family: Verdana">mt</span><span style="font-size: 9pt; font-family: 宋体">运行完成后</span><span style="font-size: 9pt; font-family: Verdana">,</span><span style="font-size: 9pt; font-family: 宋体">我们让主线程休息一下，然后我们再次在这个线程对象上启动线程</span><span style="font-size: 9pt; font-family: Verdana">.</span><span style="font-size: 9pt; font-family: 宋体">结果我们看到：</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; color: red; font-family: Verdana">Exception in thread "main" java.lang.IllegalThreadStateException</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; color: red; font-family: 宋体">根本原因是在以下源代码中找出：</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; color: red; font-family: Verdana">public&nbsp;synchronized&nbsp;void&nbsp;start()&nbsp;{</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; color: red; font-family: Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(started)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;IllegalThreadStateException();</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; color: red; font-family: Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;started&nbsp;=&nbsp;true;</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; color: red; font-family: Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;group.add(this);</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; color: red; font-family: Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start0();</span></p>
<p style="margin-left: 21pt"><span style="font-size: 9pt; color: red; font-family: Verdana">&nbsp;}</span></p>
<p style="margin-left: 21pt"><span style="color: black; font-family: 宋体">一个</span><span style="color: black; font-family: Verdana">Thread</span><span style="color: black; font-family: 宋体">的实例一旦调用</span><span style="color: black; font-family: Verdana">start()</span><span style="color: black; font-family: 宋体">方法，这个实例的</span><span style="color: black; font-family: Verdana">started</span><span style="color: black; font-family: 宋体">标记就标记为</span><span style="color: black; font-family: Verdana">true</span><span style="color: black; font-family: 宋体">，事实中不管这个线程后来有没有执行到底，只要调用了一次</span><span style="color: black; font-family: Verdana">start()</span><span style="color: black; font-family: 宋体">就再也没有机会运行了，这意味着：</span></p>
<p style="margin-left: 21pt"><span style="color: black; font-family: 宋体">【通过</span><span style="color: black; font-family: Verdana">Thread</span><span style="color: black; font-family: 宋体">实例的</span><span style="color: black; font-family: Verdana">start()</span><span style="color: black; font-family: 宋体">，一个</span><span style="color: black; font-family: Verdana">Thread</span><span style="color: black; font-family: 宋体">的实例只能产生一个线程】</span></p>
<h2>interrupt()<span style="font-family: 黑体">方法</span></h2>
<p style="margin-left: 21pt; text-indent: 21pt"><span style="color: black; font-family: 宋体">当一个线程对象调用</span><span style="color: black; font-family: Verdana">interrupt()</span><span style="color: black; font-family: 宋体">方法，它对应的线程并没有被中断，只是改变了它的中断状态。使当前线程的状态变以中断状态，如果没有其它影响，线程还会自己继续执行。只有当线程执行到</span><span style="color: black; font-family: Verdana">sleep</span><span style="color: black; font-family: 宋体">，</span><span style="color: black; font-family: Verdana">wait</span><span style="color: black; font-family: 宋体">，</span><span style="color: black; font-family: Verdana">join</span><span style="color: black; font-family: 宋体">等方法时，或者自己检查中断状态而抛出异常的情况下，线程才会抛出异常。</span></p>
<h2>join()<span style="font-family: 黑体">方法</span></h2>
<p style="margin-left: 21pt; text-indent: 21pt">join()<span style="font-family: 宋体">方法，正如第一节所言，在一个线程对象上调用</span>join<span style="font-family: 宋体">方法，是当前线程等待这个线程对象对应的线程结束</span></p>
<p style="margin-left: 21pt"><span style="font-family: 宋体">例如：有两个工作，工作</span>A<span style="font-family: 宋体">要耗时</span>10<span style="font-family: 宋体">秒钟，工作</span>B<span style="font-family: 宋体">要耗时</span>10<span style="font-family: 宋体">秒或更多。我们在程序中先生成一个线程去做工作</span>B<span style="font-family: 宋体">，然后做工作</span>A<span style="font-family: 宋体">。</span></p>
<p style="margin-left: 21pt; text-align: center" align="center">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong><em><span style="font-size: 12pt">new B().start();//</span></em></strong><strong><em><span style="font-size: 12pt; font-family: 宋体">做工作</span></em></strong><strong><em><span style="font-size: 12pt">B</span></em></strong></p>
<p style="margin-left: 21pt; text-align: center" align="center"><strong><em><span style="font-size: 12pt">A();//</span></em></strong><strong><em><span style="font-size: 12pt; font-family: 宋体">做工作</span></em></strong><strong><em><span style="font-size: 12pt">A</span></em></strong></p>
<p style="margin-left: 21pt"><span style="font-family: 宋体">工作</span>A<span style="font-family: 宋体">完成后，下面要等待工作</span>B<span style="font-family: 宋体">的结果来进行处理。如果工作</span>B<span style="font-family: 宋体">还没有完成我就不能进行下面的工作</span>C<span style="font-family: 宋体">，所以：</span></p>
<p style="margin-left: 21pt; text-align: center" align="center"><strong><em><span style="font-size: 12pt">B b = new B();</span></em></strong></p>
<p style="margin-left: 21pt; text-align: center" align="center"><strong><em><span style="font-size: 12pt">b.start();//</span></em></strong><strong><em><span style="font-size: 12pt; font-family: 宋体">做工作</span></em></strong><strong><em><span style="font-size: 12pt">B</span></em></strong></p>
<p style="margin-left: 21pt; text-align: center" align="center"><strong><em><span style="font-size: 12pt">A();//</span></em></strong><strong><em><span style="font-size: 12pt; font-family: 宋体">做工作</span></em></strong><strong><em><span style="font-size: 12pt">A</span></em></strong></p>
<p style="margin-left: 21pt; text-align: center" align="center"><strong><em><span style="font-size: 12pt">b.join();//</span></em></strong><strong><em><span style="font-size: 12pt; font-family: 宋体">等工作</span></em></strong><strong><em><span style="font-size: 12pt">B</span></em></strong><strong><em><span style="font-size: 12pt; font-family: 宋体">完成</span></em></strong><strong><em><span style="font-size: 12pt">.</span></em></strong></p>
<p style="margin-left: 21pt; text-align: center" align="center"><strong><em><span style="font-size: 12pt">C();//</span></em></strong><strong><em><span style="font-size: 12pt; font-family: 宋体">继续工作</span></em></strong><strong><em><span style="font-size: 12pt">C</span></em></strong></p>
<p style="margin-left: 21pt"><span style="font-family: 宋体">原则：【</span>join<span style="font-family: 宋体">是测试其它工作状态的唯一正确方法】</span></p>
<h2>yield()<span style="font-family: 黑体">方法</span></h2>
<p style="margin-left: 21pt; text-indent: 21pt">yield()<span style="font-family: 宋体">方法也是类方法，只在当前线程上调用，理由同上，它主是让当前线程放弃本次分配到的时间片，调用这个方法不会提高任何效率，只是降低了</span>CPU<span style="font-family: 宋体">的总周期上面介绍的线程一些方法，基于</span>(<span style="font-family: 宋体">基础篇</span>)<span style="font-family: 宋体">而言只能简单提及。以后具体应用中我会结合实例详细论述。</span></p>
<p style="margin-left: 21pt"><span style="font-family: 宋体">原则：【不是非常必要的情况下，没有理由调用它】</span></p>
<h2>wait()<span style="font-family: 黑体">、</span>notify()/notityAll()<span style="font-family: 黑体">方法</span></h2>
<p style="margin-left: 21pt; text-indent: 21pt"><span style="color: black; font-family: 宋体">首先明确一点他们的属于普通对象方法，并非是线程对象方法；其次它们只能在同步方法中调用。线程要想调用一个对象的</span><span style="color: black; font-family: Verdana">wait()</span><span style="color: black; font-family: 宋体">方法就要先获得该对象的监视锁</span><span style="color: black; font-family: Verdana">,</span><span style="color: black; font-family: 宋体">而一旦调用</span><span style="color: black; font-family: Verdana">wait()</span><span style="color: black; font-family: 宋体">后又立即释放该锁。</span></p>
<h2><span style="font-family: 黑体">线程的互斥控制</span></h2>
<p style="margin-left: 21pt; text-indent: 21pt"><span style="color: black; font-family: 宋体">多个线程同时操作某一对象时，一个线程对该对象的操作可能会改变其状态，而该状态会影响另一线程对该对象的真正结果。</span></p>
<h2>synchornized<span style="font-family: 黑体">关键字</span></h2>
<p style="margin-left: 21pt; text-indent: 21pt"><span style="color: black; font-family: 宋体">把一个单元声明为</span><span style="color: black; font-family: Verdana">synchornized,</span><span style="color: black; font-family: 宋体">就可以让在同一时间只有一个线程操作该方法。作为记忆可以把</span><span style="color: black; font-family: Verdana">synchronized</span><span style="color: black; font-family: 宋体">看作是一个锁。但是我们要理解锁是被动的，还是主动的呢？换而言之它到底锁什么了？锁谁了？</span></p>
<p style="margin-left: 21pt; text-indent: 21pt"><span style="color: black; font-family: 宋体">例如：</span></p>
<p style="margin-left: 21pt; text-indent: 21pt"><span style="color: black; font-family: Verdana">synchronized(obj){</span></p>
<p><span style="color: black; font-family: Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //todo&#8230;</span></p>
<p style="margin-left: 21pt; text-indent: 21pt"><span style="color: black; font-family: Verdana">}</span></p>
<p style="margin-left: 21pt; text-indent: 21pt"><span style="color: black; font-family: 宋体">如果代码运行到此处，</span><span style="color: black; font-family: Verdana">synchronized</span><span style="color: black; font-family: 宋体">首先获取</span><span style="color: black; font-family: Verdana">obj</span><span style="color: black; font-family: 宋体">参数对象的锁，若没有获取线程只能等待，如果多个线程运行到这只能有一个线程获取</span><span style="color: black; font-family: Verdana">obj</span><span style="color: black; font-family: 宋体">的锁，然后再执行</span><span style="color: black; font-family: Verdana">{}</span><span style="color: black; font-family: 宋体">中的代码。因此</span><span style="color: black; font-family: Verdana">obj</span><span style="color: black; font-family: 宋体">作用范围不同，控制程序也不同。</span></p>
<p style="margin-left: 21pt"><strong><span style="color: black; font-family: 宋体">如果一个方法声明为</span></strong><strong><span style="color: black; font-family: Verdana">synchornized</span></strong><strong><span style="color: black; font-family: 宋体">的，则等同于把在为个方法上调用</span></strong><strong><span style="color: black; font-family: Verdana">synchornized(this)</span></strong><strong><span style="color: black; font-family: 宋体">。</span></strong></p>
<p style="margin-left: 21pt"><strong><span style="color: black; font-family: 宋体">如果一个静态方法被声明为</span></strong><strong><span style="color: black; font-family: Verdana">synchornized</span></strong><strong><span style="color: black; font-family: 宋体">，则等同于把在为个方法上调用</span></strong><strong><span style="color: black; font-family: Verdana">synchornized(</span></strong><strong><span style="color: black; font-family: 宋体">类</span></strong><strong><span style="color: black; font-family: Verdana">.class)</span></strong></p>
<p style="margin-left: 21pt"><strong>&nbsp;</strong></p>
<h2><span style="font-family: 黑体">真正的停止线程</span></h2>
<p><span style="font-family: 宋体">要让一个线程得到真正意义的停止，需要了解当前的线程在干什么，如果线程当前没有做什么，那立刻让对方退出，当然是没有任何问题，但是如果对方正在手头赶工，那就必须让他停止，然后收拾残局。因此，首先需要了解步骤：</span></p>
<p style="margin-left: 18pt; text-indent: -18pt; tab-stops: list 18.0pt"><span style="color: black; font-family: Verdana">1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color: black; font-family: 宋体">正常运行；</span></p>
<p style="margin-left: 18pt; text-indent: -18pt; tab-stops: list 18.0pt">2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: black; font-family: 宋体">处理结束前的工作</span><span style="color: black; font-family: Verdana">,</span><span style="color: black; font-family: 宋体">也就是准备结束；</span></p>
<p style="margin-left: 18pt; text-indent: -18pt; tab-stops: list 18.0pt">3.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: black; font-family: 宋体">结束退出。</span></p>
注：以上部分概括出自某位牛人大哥的笔记，经常拜读他的博客
<img src ="http://www.blogjava.net/yeshucheng/aggbug/287407.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yeshucheng/" target="_blank">叶澍成</a> 2009-07-20 10:00 <a href="http://www.blogjava.net/yeshucheng/archive/2009/07/20/287407.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>认识缓冲区Buffer</title><link>http://www.blogjava.net/yeshucheng/archive/2009/02/13/254603.html</link><dc:creator>叶澍成</dc:creator><author>叶澍成</author><pubDate>Fri, 13 Feb 2009 12:56:00 GMT</pubDate><guid>http://www.blogjava.net/yeshucheng/archive/2009/02/13/254603.html</guid><wfw:comment>http://www.blogjava.net/yeshucheng/comments/254603.html</wfw:comment><comments>http://www.blogjava.net/yeshucheng/archive/2009/02/13/254603.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yeshucheng/comments/commentRss/254603.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yeshucheng/services/trackbacks/254603.html</trackback:ping><description><![CDATA[&nbsp;
<p style="text-indent: 21pt"><span style="font-family: 宋体">数据对于输入和输出的操作耗时是非常严重的问题，如果把这个问题放入到网络上去看待更甚是值得注意的一个问题了。假如结合基础的</span>OS<span style="font-family: 宋体">知识我们也知道如果要减少这种</span>I/O<span style="font-family: 宋体">操作的耗时或者也可以说提升这种效率的话，最大的可能就是减少物理读写的次数，而且尽可能做到主存数据的重读性（操作系统也在加强说明更多减少抖动现象的产生）。</span></p>
<p style="text-indent: 21pt"><span style="font-family: 宋体">在</span>java.nio<span style="font-family: 宋体">包中我们可以直接来操作相对应的</span>API<span style="font-family: 宋体">了。可以让</span>java<span style="font-family: 宋体">更加方便的直接控制和运用缓冲区。缓冲区有几个需要了解的特定概念需要详尽来解释，才能更好的知道我们下面一些列需要针对的问题实质。</span></p>
<h3><span style="font-family: 宋体">属性</span></h3>
<p><span style="font-family: 宋体">容量（</span>capacity<span style="font-family: 宋体">）：顾名思义就是表示缓冲区中可以保存多少数据；</span></p>
<p><span style="font-family: 宋体">极限（</span>limit<span style="font-family: 宋体">）：缓冲区中的当前数据终结点。不过它是可以动态改变的，这样做的好处也是充分利用重用性；</span></p>
<p><span style="font-family: 宋体">位置</span>(position)<span style="font-family: 宋体">：这个也好理解，其实就是指明下一个需要读写数据的位置。</span></p>
<p><span style="font-family: 宋体">上面上个关系还可以具体用图示的方式来表达整体概念，如下图所示：<br />
</span></p>
<span style="font-family: 宋体">
<p align="left">
<div align="center"><img height="163" alt="" src="http://www.blogjava.net/images/blogjava_net/yeshucheng/buffer.jpg" width="151" border="0" /></div>
<br />
在极限的时候就说到可以<em>修改</em>它，所以对于它的操作由以下方法：</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>clear()<span style="font-family: 宋体">：首先把极限设置为容量，再者就是需要把位置设置为</span>0<span style="font-family: 宋体">；</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>flip()<span style="font-family: 宋体">：把极限设置为位置区，再者就是需要把位置设置为</span>0<span style="font-family: 宋体">；</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>rewind()<span style="font-family: 宋体">：不改变极限，不过还是需要把位置设置为</span>0<span style="font-family: 宋体">。</span></p>
<p><span style="font-family: 宋体">最为最基础的缓冲区</span>ByteBuffer<span style="font-family: 宋体">，它存放的数据单元是字节。首先要强调的是</span>ByteBuffer<span style="font-family: 宋体">没有提供公开的构造方法，只是提供了两个静态的工厂方法。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>allocate(int capacity)<span style="font-family: 宋体">：返回一个</span>ByteBuffer<span style="font-family: 宋体">对象，参数表示缓冲区容量大小。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>allocateDirect (int capacity)<span style="font-family: 宋体">：返回一个</span>ByteBuffer<span style="font-family: 宋体">对象，参数也是一样表示缓冲区容量大小。</span></p>
<p><span style="font-family: 宋体">在这里需要注意的是在使用两者的时候需要特别小心，</span>allocateDirect<span style="font-family: 宋体">和当前操作系统联系的非常紧密，它牵涉到使用</span>native method<span style="font-family: 宋体">的方法，大家知道一旦本地方法就是需要考虑调用</span>dll<span style="font-family: 宋体">（动态链接库）这个时候基本也就失去了</span>JAVA<span style="font-family: 宋体">语言的特性，言外之意对于耗资源非常大。所以如果考虑到当前使用的缓存区比较庞大而且是一个长期驻留使用的，这个时候可以考虑使用它。</span></p>
 <img src ="http://www.blogjava.net/yeshucheng/aggbug/254603.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yeshucheng/" target="_blank">叶澍成</a> 2009-02-13 20:56 <a href="http://www.blogjava.net/yeshucheng/archive/2009/02/13/254603.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从套接字衍生到RMI代码思路</title><link>http://www.blogjava.net/yeshucheng/archive/2009/02/03/253144.html</link><dc:creator>叶澍成</dc:creator><author>叶澍成</author><pubDate>Tue, 03 Feb 2009 13:56:00 GMT</pubDate><guid>http://www.blogjava.net/yeshucheng/archive/2009/02/03/253144.html</guid><wfw:comment>http://www.blogjava.net/yeshucheng/comments/253144.html</wfw:comment><comments>http://www.blogjava.net/yeshucheng/archive/2009/02/03/253144.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/yeshucheng/comments/commentRss/253144.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yeshucheng/services/trackbacks/253144.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在上篇blog中谈到RMI的问世由来只是大致的把一些概念结构说明了下，自己静静想想要有好的说明干脆用代码说明比较妥当也最为有说明性。事后自己倒腾了一个简单的代码DEMO。代码中有个简单的场景，比如你是属于某地区医保范围内的成员，到医院看病，这个候医院为了审核你的相关个人资料需要到医保管理部门调阅信息，你只需要给出用户名称或者其他一个有...&nbsp;&nbsp;<a href='http://www.blogjava.net/yeshucheng/archive/2009/02/03/253144.html'>阅读全文</a><img src ="http://www.blogjava.net/yeshucheng/aggbug/253144.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yeshucheng/" target="_blank">叶澍成</a> 2009-02-03 21:56 <a href="http://www.blogjava.net/yeshucheng/archive/2009/02/03/253144.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>RMI的原理和实现</title><link>http://www.blogjava.net/yeshucheng/archive/2009/02/02/252932.html</link><dc:creator>叶澍成</dc:creator><author>叶澍成</author><pubDate>Mon, 02 Feb 2009 04:04:00 GMT</pubDate><guid>http://www.blogjava.net/yeshucheng/archive/2009/02/02/252932.html</guid><wfw:comment>http://www.blogjava.net/yeshucheng/comments/252932.html</wfw:comment><comments>http://www.blogjava.net/yeshucheng/archive/2009/02/02/252932.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/yeshucheng/comments/commentRss/252932.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yeshucheng/services/trackbacks/252932.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
&nbsp;
<h2><span style="font-family: 黑体">综述</span></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rmi<span style="font-family: 宋体">自从</span>JDK1.1<span style="font-family: 宋体">就已经出现了。而对于为什么在</span>JAVA<span style="font-family: 宋体">的世界里需要一个这样</span> <span style="font-family: 宋体">思想理念就需要看下：</span><a href="http://www.blogjava.net/yeshucheng/archive/2009/02/02/252931.html">RMI<span style="font-family: 宋体">问世由来</a></span><span style="font-family: 宋体">。其实真正在国内使用到它的比较少，不过在前些年比较火的</span>EJB<span style="font-family: 宋体">就是在它的基础上进一步深化的。从本质上来讲</span>RMI<span style="font-family: 宋体">的兴起正是为了设计分布式的客户、服务器结构需求而应运而生的，而它的这种</span>B/S<span style="font-family: 宋体">结构思想能否和我们通常的</span>JAVA<span style="font-family: 宋体">编程更加贴切呢？言外之意就是能否让这种分布式的状态做到更加透明，作为开发人员只需要按照往常一样开发</span>JAVA<span style="font-family: 宋体">应用程序一样来开发分布式的结构。那现在的问题是如何来划平这个鸿沟呢？首先我们来分析下在</span>JAVA<span style="font-family: 宋体">世界里它的一些特点因素：</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>JAVA<span style="font-family: 宋体">使用垃圾收集确定对象的生命周期。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>JAVA<span style="font-family: 宋体">使用异常处理来报告运行期间的错误。这里就要和我们网络通讯中的异常相联系起来了。在</span>B/S<span style="font-family: 宋体">结构的网络体系中我们的这种错误性是非常常见的。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>JAVA<span style="font-family: 宋体">编写的对象通过调用方法来调用。由于网络通讯把我们的客户与服务器之间阻隔开了。但是代理的一种方式可以很好的提供一种这样的假象，让开发人员或者使用者都感觉是在本地调用。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>JAVA<span style="font-family: 宋体">允许一种高级的使用类加载器（</span>CLassLoader<span style="font-family: 宋体">）机制提供系统类路径中没有的类。这话什么意思？</span></p>
<h2><span style="font-family: 黑体">主要特点</span></h2>
<p style="margin-left: 21pt"><span style="font-family: 宋体">上面说到了分布式的方式和我们的</span>JAVA<span style="font-family: 宋体">中如何更好的划平这个鸿沟，需要具备的特质。</span></p>
<p><span style="font-family: 宋体">那这里我们来看看我们所谓的</span>RMI<span style="font-family: 宋体">到底跟我们普通的</span>JAVA<span style="font-family: 宋体">（或者说</span>JavaBean<span style="font-family: 宋体">）存在一些什么样的差异：</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong>RMI</strong><strong><span style="font-family: 宋体">远程异常（</span>Remote Exception</strong><strong><span style="font-family: 宋体">）：</span></strong><span style="font-family: 宋体">在上面我们也提到了一个网络通讯难免有一些无论是软件级别的还是硬件级别的异常现象，有时候这些异常或许是一种无法预知的结果。让我们开发人缘如何来回溯这种异常信息，这个是我们开发人员要关心的。因此在调用远程对象的方法中我们必须在远程接口中（接口是一种规范的标准行为）所以在调用的这个方法体上需要签名注明：</span>java.rmi,RemoteException.<span style="font-family: 宋体">。这也就注明了此方法是需要调用远程对象的。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span style="font-family: 宋体">值传递</span> </strong><span style="font-family: 宋体">：当把对象作为参数传递给一个普通的</span>JAVA<span style="font-family: 宋体">对象方法调用时，只是传递该对象的<strong><em>引用</em></strong>。请注意这里谈到的是对象的&#8220;引用&#8221;一词，如果在修改该参数的时候，是直接修改原始对象。它并不是所谓的一个对象的备份或者说拷贝（说白了就是在本</span>JVM<span style="font-family: 宋体">内存中的对象）。但是如果说使用的是</span>RMI<span style="font-family: 宋体">对象，则完全是拷贝的。这与普通对象有着鲜明的对比。也正是由于这种拷贝的资源消耗造就了下面要说到的性能缺失了。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span style="font-family: 宋体">调用开销</span></strong><span style="font-family: 宋体">：凡是经过网络通讯理论上来说都是一种资源的消耗。它需要通过编组与反编组方式不断解析类对象。而且</span>RMI<span style="font-family: 宋体">本身也是一种需要返回值的一个过程定义。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="font-family: Wingdings">l<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span style="font-family: 宋体">安全性</span></strong><span style="font-family: 宋体">：一谈到网络通讯势必会说到如何保证安全的进行。</span></p>
<p><strong>&nbsp;</strong></p>
<h2><span style="font-family: 黑体">概念定义</span></h2>
<p style="text-indent: 21pt"><span style="font-family: 宋体">在开始进行原理梳理之前我们需要定义清楚几个名词。对于这些名词的理解影响到后的深入进行。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt">1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong>Stub</strong><span style="font-family: 宋体">（存根，有些书上也翻译成：桩基在</span>EJB<span style="font-family: 宋体">的相关书籍中尤为体现这个意思）：</span></p>
<p style="text-indent: 21pt"><span style="font-family: 宋体">这里举例说明这个概念起（或许不够恰当）。例如大家因公出差后，都有存在一些报销的发票或者说小票。对于你当前手头所拿到的发票并不是一个唯一的，它同时还在你发生消费的地点有一个复印件，而这个复印件就是所谓的存根。但是这个存根上并没有很多明细的描述，只是有一个大概的金额定义。它把很多的细节费用都忽略了。所以这个也是我们说的存根定义。而在我们</span>RMI<span style="font-family: 宋体">的存根定义就是使用了这样一个理解：在与远程发生通讯调用时，把通讯调用的所有细节都通过对象的封装形式给隐藏在后端。这本身就符合</span>OOAD<span style="font-family: 宋体">的意思理念。而暴露出来的就是我们的接口方式，而这种接口方式又和服务器的对象具有相同的接口（这里就和我们前面举例说的报销单据联系上了，报销单据的存根不知道会有一个什么形式发生具体问题，而你手执的发票具体就需要到贵公司去报销费用，而这里的公司财务处就是所谓的服务器端，它才是真正干实质性问题的。）因此作为开发人员只需要把精力集中在业务问题的解决上，而不需要考虑复杂的分布式计算。所有这些问题都交给</span>RMI<span style="font-family: 宋体">去一一处理。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt">2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong>Skeleton</strong>(<span style="font-family: 宋体">一些书翻译叫骨架，也叫结构体</span>)<span style="font-family: 宋体">：它的内部就是真正封装了一个类的形成调用体现机制。包括我们熟知的</span>ServerSocket<span style="font-family: 宋体">创建、接受、监听、处理等。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt">3.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong>Mashalling</strong>(<span style="font-family: 宋体">编组</span>)<span style="font-family: 宋体">：在内存中的对象转换成字节流，以便能够通过网络连接传输。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt">4.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong>Unmashalling</strong>(<span style="font-family: 宋体">反编组</span>)<span style="font-family: 宋体">：在内存中把字节流转换成对象，以便本地化调用。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt">5.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong>Serialization</strong>(<span style="font-family: 宋体">序列化</span>)<span style="font-family: 宋体">：编组中使用到的技术叫序列化。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt">6.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong>Deserializationg</strong>(<span style="font-family: 宋体">反序列化</span>)<span style="font-family: 宋体">：反编组中使用到的技术叫反序列化。</span></p>
<p><strong>&nbsp;</strong></p>
<h2><span style="font-family: 黑体">客户端</span></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">既然我们知道</span>stub<span style="font-family: 宋体">主要是以接口的方式来暴露体现，而</span>stub<span style="font-family: 宋体">主要</span> <span style="font-family: 宋体">也是以代理的方式来具体实施。那在</span>RMI<span style="font-family: 宋体">中的这种接口有哪些特性呢？（</span>Remote Interface<span style="font-family: 宋体">）</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt">1)<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">必须扩展（</span>extends<span style="font-family: 宋体">）</span>java.rmi.Remote<span style="font-family: 宋体">接口，因为远程接口并不包含任何一个方法，而是作为一个标记出现</span><span style="font-family: 宋体">，它就是需要告诉</span>JVM<span style="font-family: 宋体">在</span>RunTime<span style="font-family: 宋体">的时候哪些是常规对象，哪些属于远程对象。通过这种标识的定义能让</span>JVM<span style="font-family: 宋体">了解类中哪些方法需要编组，通过了编组的方式才能通过网络序列化的调用；</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt">2)<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">接口必须为</span>public<span style="font-family: 宋体">（公共），它的好处不言而喻的——能够方便的让所有人员来调用。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt">3)<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">接口方法还需要以异常抛出（例如：</span>RemoteException<span style="font-family: 宋体">），至于它的用处我们在前面也提到这里就不再复述；</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt">4)<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">在调用一个远程对象期间（运行期间），方法的参数和返回值都要必须是可序列化的。至于为什么需要这么做？这里的缘由不用多说大家也应该清楚了解。</span></p>
<h2><span style="font-family: 黑体">服务端</span></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">既然我们知道</span>stub<span style="font-family: 宋体">所做的事情是一个简单的代理转发动作，那我们真正要做的对象就在服务端来做了。对于使用简单的</span>RMI<span style="font-family: 宋体">我们直接去指定，但是往往一旦使用了</span>RMI<span style="font-family: 宋体">对象就存在非常多的远程方法调用，这个时候服务器端对于这么多的调用如何来判别或者说识别呢？这里就要说到的是对于</span>RMI<span style="font-family: 宋体">实现它会创建一个标识符，以便以后的</span>stub<span style="font-family: 宋体">可以调用转发给服务器对象使用了，而这种方式我们通常叫服务器</span>RMI<span style="font-family: 宋体">的注册机制。言外之意就是让服务器端的对象注册在</span>RMI<span style="font-family: 宋体">机制中，然后可以导出让今后的</span>stub<span style="font-family: 宋体">按需来调用。那它又是如何做到这种方式的呢？对于</span>RMI<span style="font-family: 宋体">来说有两种方式可以达到这种效果：</span></p>
<p style="margin-left: 41.95pt; text-indent: -21pt; tab-stops: list 41.95pt">a)<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">直接使用</span>UnicastRemoteObject<span style="font-family: 宋体">的静态方法：</span>exportObject<span style="font-family: 宋体">；</span></p>
<p style="margin-left: 41.95pt; text-indent: -21pt; tab-stops: list 41.95pt">b)<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">继承</span>UnicastRemoteObject<span style="font-family: 宋体">类则缺省的构造函数</span>exportObject<span style="font-family: 宋体">。</span></p>
<p style="text-indent: 20.95pt"><span style="font-family: 宋体">现在大家又会问他们之间又有什么区别呢？我该使用哪种方式来做呢，这不是很难做抉择吗？从一般应用场景来说区别并不是很大，但是，这里说了&#8220;但是&#8221;哦，呵呵。大家知道继承的方式是把父类所具备的所有特质都可以完好无损的继承到子类中而对于类的总老大：</span>Object<span style="font-family: 宋体">来说里面有：</span>equals()<span style="font-family: 宋体">、</span>hashCode()<span style="font-family: 宋体">、</span>toString()<span style="font-family: 宋体">等方法。这是个什么概念呢？意思就是说如果对于本地化的调用，他们两个的方法（</span>a,b<span style="font-family: 宋体">）基本区别不是很大。但是我们这里强调的</span>RMI<span style="font-family: 宋体">如果是一种分布式的特定场景，具备使用哈希表这种特性就显得尤为重要了。</span></p>
<p style="text-indent: 20.95pt"><span style="font-family: 宋体">刚才说了服务端采用什么方法行为导出对象的。那现在导出后的对象又对应会发生什么情况呢？</span></p>
<p style="text-indent: 20.95pt"><span style="font-family: 宋体">首先被导出的对象被分配一个标识符，这个标识符被保存为：</span>java.rmi.server.ObjID<span style="font-family: 宋体">对象中并被放到一个对象列表中或者一个映射中。而这里的</span>ID<span style="font-family: 宋体">是一个关键字，而远程对象则是它的一个值（说到这大家有没有觉得它原理非常像</span>HashMap<span style="font-family: 宋体">的特质呢？没错，其实就是使用了它的特性），这样它就可以很好的和前面创建的</span>stub<span style="font-family: 宋体">沟通。如果调用了静态方法</span>UnicastRemoteObject.export(Remote &#8230;)<span style="font-family: 宋体">，</span>RMI<span style="font-family: 宋体">就会选择任意一个端口号，但这只是第一调用发生在随后的</span>exportObject<span style="font-family: 宋体">每次调用都把远程对象导出到该远程对象第一被导出时使用的端口号。这样就不会产生混乱，会把先前一一导出的对象全部放入到列表中。当然如果采用的是指定端口的，则按照对应显示的调用方式使用。这里稍作强调的是一个端口可以导出任意数目的对象。</span></p>
<span style="font-size: 10.5pt; font-family: 宋体">（待续</span><span style="font-size: 10.5pt; font-family: 'Times New Roman'">&#8230;&#8230;</span><span style="font-size: 10.5pt; font-family: 宋体">）</span>
 <img src ="http://www.blogjava.net/yeshucheng/aggbug/252932.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yeshucheng/" target="_blank">叶澍成</a> 2009-02-02 12:04 <a href="http://www.blogjava.net/yeshucheng/archive/2009/02/02/252932.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>RMI问世由来</title><link>http://www.blogjava.net/yeshucheng/archive/2009/02/02/252931.html</link><dc:creator>叶澍成</dc:creator><author>叶澍成</author><pubDate>Mon, 02 Feb 2009 03:57:00 GMT</pubDate><guid>http://www.blogjava.net/yeshucheng/archive/2009/02/02/252931.html</guid><wfw:comment>http://www.blogjava.net/yeshucheng/comments/252931.html</wfw:comment><comments>http://www.blogjava.net/yeshucheng/archive/2009/02/02/252931.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/yeshucheng/comments/commentRss/252931.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yeshucheng/services/trackbacks/252931.html</trackback:ping><description><![CDATA[<span style="font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;大家都知道对于互联网的世界网络通讯是其本质特征。而对于一个分布式式计算来说更是如此。在它的环境中使用了客户</span>/<span style="font-family: 宋体">服务器结构特点，使用的一个核心技术就是网络通讯层。在最早的</span>OSI<span style="font-family: 宋体">的概念基础上，建立了完善具体协议层。而客户想要能够与位于其他物理层主机上的服务器通讯，需要能够想服务器发送数据，然后以某种方式获得响应。这当中就牵涉到我们熟悉的协议层面了，在这里就不再复述这些协议概念了。对于网络通讯来说我们所要了解的是最为常用的就是两种连接方式：无连接协议（</span>UDP<span style="font-family: 宋体">）、面向连接协议（</span>TCP/IP<span style="font-family: 宋体">）。</span>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">多数网络编程库中（以</span>JAVA<span style="font-family: 宋体">为主来说明），在</span>JAVA<span style="font-family: 宋体">平台中一样的提供了这些元素。而作为面向连接协议来说使用的是套接字（</span>Socket<span style="font-family: 宋体">）进行了更进一步的抽象描述。一般我们在</span>JAVA<span style="font-family: 宋体">的网络编程中都觉得在使用套接字这块相对方便，它不需要你去更多的了解操作系统的细节以及硬件的传递处理方式。</span>TCP/IP<span style="font-family: 宋体">的所有细节之处都得到了套接字的封装使用，让程序员关注到业务层面的处理。</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">对象是一种抽象思维物质，对于计算机来说它只对数字电路的存储方式能够加以识别而且在网络传输当中也是一种信号量，而这一切只有使用字节流方式传输才是真正需要做到的。所以在本地主机与远程服务器的通讯传输就在对象与字节流之间不断相互转化才是我们真正需要的人性物质与机器所需要的。（有点墨迹了，切入整体）总体来说就是需要两种方式来认定这种传输行为：编组（</span>Marshalling<span style="font-family: 宋体">）与反编组（</span>Unmarshalling<span style="font-family: 宋体">）。而这一切的手段方式才是通过：序列化（</span>Serialiazable<span style="font-family: 宋体">）与反序列化的方式不断完成。如下图所示：
<div align="center"><img height="99" alt="" src="http://www.blogjava.net/images/blogjava_net/yeshucheng/clip_image002.jpg" width="491" border="0" /></div>
</span>
<p>&nbsp;</p>
<p style="text-align: center" align="center"><span style="font-size: 9pt; font-family: 宋体">图：对象到字节再到对象的转换</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">对于数据的传输本质就是上图说明的。那我们一般是如何使用套接字来构造我们这一行为呢？对于这里强调的主要是一种大致方法说明，所以只能以部分代码来说明客户端怎么来发送这个请求。</span></p>
<div style="border-right: windowtext 1pt solid; padding-right: 4pt; border-top: windowtext 1pt solid; padding-left: 4pt; background: #d9d9d9; padding-bottom: 1pt; border-left: windowtext 1pt solid; padding-top: 1pt; border-bottom: windowtext 1pt solid">
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; text-indent: 21pt; padding-top: 0cm; border-bottom: medium none; text-align: left" align="left"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">Socket </span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">socket</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">=</span><strong><span style="font-size: 10pt; color: #7f0055; font-family: 'Courier New'">new</span></strong><span style="font-size: 10pt; color: black; font-family: 'Courier New'"> Socket(</span><span style="font-size: 10pt; color: #2a00ff; font-family: 'Courier New'">"http://www.wgh.com.cn"</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">,8888);</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none; text-align: left" align="left"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; OutputStream </span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">out</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">=</span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">socket</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">.getOutputStream();</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none; text-align: left" align="left"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;ObjectOutputStream </span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">obj</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">=</span><strong><span style="font-size: 10pt; color: #7f0055; font-family: 'Courier New'">new</span></strong><span style="font-size: 10pt; color: black; font-family: 'Courier New'"> ObjectOutputStream(</span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">out</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">);</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none; text-align: left" align="left"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; obj<u>.</u>writeObject(<u>object</u>);</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none; text-align: left" align="left"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp;</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;InputStream </span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">in</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">=</span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">socket</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">.getInputStream();</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none; text-align: left" align="left"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; ObjectInputStream </span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">objIn</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">=</span><strong><span style="font-size: 10pt; color: #7f0055; font-family: 'Courier New'">new</span></strong><span style="font-size: 10pt; color: black; font-family: 'Courier New'"> ObjectInputStream(</span><span style="font-size: 10pt; color: #0000c0; font-family: 'Courier New'">in</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">);</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none; text-align: left" align="left"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; Object objFoo=(Object)objIn.readObject();</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none; text-align: left" align="left"><span style="font-size: 10pt; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; //todo </span><span style="font-size: 10pt; font-family: 宋体">这里就是具体进行操作的相关传值参数处理了</span><span style="font-size: 10pt; font-family: 'Courier New'">&#8230;</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none; text-align: left" align="left"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; obj.<u>close</u>();</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none; text-align: left" align="left"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; objIn.<u>close</u>();</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; socket.<u>close</u>();</span></p>
</div>
<p style="text-indent: 21pt"><span style="font-size: 10pt; color: black; font-family: 宋体">而作为服务器的接收方则把以上数据做一个逆转相反处理就可以。即服务器需要读取发送过来的对象数据，最终得到结果。现在假设还是一个甚至更多这样的对象处理，我们又要处理和以上代码差不多的过程。好，到这里我们可曾想到难道没有一种办法把这些过多的重复过程做一个通用的方式来提供吗？我如果不想去做这些繁杂的对象处理可以吗？比如，我想直接得到：</span></p>
<div style="border-right: windowtext 1pt solid; padding-right: 4pt; border-top: windowtext 1pt solid; padding-left: 4pt; background: #d9d9d9; padding-bottom: 1pt; border-left: windowtext 1pt solid; padding-top: 1pt; border-bottom: windowtext 1pt solid">
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">//</span><span style="font-size: 10pt; color: black; font-family: 宋体">其中</span><span style="font-size: 10pt; color: black; font-family: 'Courier New'">clientObjectji</span><span style="font-size: 10pt; color: black; font-family: 宋体">就是从客户端传输过来的副本；</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; background: #d9d9d9; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none"><span style="font-size: 10pt; color: black; font-family: 'Courier New'">MyObject myObject=server.getFoo(clientObject);</span></p>
</div>
<p><span style="color: black; font-family: 宋体">这样就能让我们把底层的那些庞杂数据转换能够透明封装起来呢？既然这个问题一经提出，那就意味着肯定有很多类似的需求。技术永远都是在需求的提出应运而生的。上面提出的需求就是我们要讨论的，既然我们想把一些套接字的重复处理过程来个封装清理，那需要面对的问题是什么呢？</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="color: black; font-family: 'Courier New'">1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color: black; font-family: 宋体">能够把所有的相同处理过程全部都移入到服务端呢？</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="color: black; font-family: 'Courier New'">2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color: black; font-family: 宋体">对于客户端来说能否只预留接口行为呢？</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="color: black; font-family: 'Courier New'">3.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color: black; font-family: 宋体">把过多的复杂处理过程完善的做个封装？</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="color: black; font-family: 'Courier New'">4.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color: black; font-family: 宋体">如果以上过程能够形成，那客户端又是如何办到可以连接到服务器端的组件行为呢？</span></p>
<p style="margin-left: 21pt"><span style="color: black; font-family: 宋体">既然能够把遇到的问题提出然后总结出来也就意味着我们需要去解决它。不知道是否还</span></p>
<p><span style="color: black; font-family: 宋体">记得设计模式中有一个叫：代理模式？没错，就是这个代理模式开始我们的描述。代理是一个实现给定接口的对象，但是不直接去执行代码结果，而是代表其他一些对象执行实际计算的对象。怎么理解这个话呢？举例说，如今很多城市都有火车票或者飞机票的代售点，这里的代售点其实就是采用了一种代理机制。我们想买某天的火车或者飞机票有时候并不需要到火车站或者飞机票的总点去购买票，而是找一个你最近的代售点去购买。代售点就是起到一个中间桥梁的作用，至于买票人员无需关心他们如何去订购，这些具体的动作都由他们内部去处理，你只关心最终是否有你需要的票就行。知道这个原理接下来就好理解很多了，我们最好以类图的方式来说明这个代理的机制，如图所示：
<div align="center"><img height="150" alt="" src="http://www.blogjava.net/images/blogjava_net/yeshucheng/clip_image2.jpg" width="443" border="0" /></div>
<br />
</span>
<p>&nbsp;</p>
<p><span style="color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; </span><span style="color: black; font-family: 宋体">到这里如果还觉得抽象，没关系接下来我以更加贴切的实例来结合类图的方式给出对应的参照说明。假如我们把上面的</span><span style="color: black; font-family: 'Courier New'">proxy</span><span style="color: black; font-family: 宋体">模式再做个深入的探讨剖析（结合上面说的客户端发送参数作为请求和提出的问题综述）。大家都知道一个接口是能够在安全甚至在扩展上能够帮助我们非常大的功能。作为客户端最为希望的就是只关心我们需要的参数（或者变量）、返回值，而它如何而来，做了哪些具体工作这些都不是客户端关心的。</span><span style="color: black; font-family: 'Courier New'">Ok,</span><span style="color: black; font-family: 宋体">现在结合我们说的接口方式，确实可以解决这个问题（接口的简单化，没有具体实现），但是你可能会问：</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="color: black; font-family: 'Courier New'">1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color: black; font-family: 宋体">既然接口如此简单，那参数又是如何传递过去的呢？</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt"><span style="color: black; font-family: 'Courier New'">2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color: black; font-family: 宋体">服务端又如何知道我要的是什么呢？</span></p>
<p style="text-indent: 21pt"><span style="color: black; font-family: 宋体">带着问题我们来解决这个问题，当然也是大家所关心的问题了。现在开始要对于上面的</span><span style="color: black; font-family: 'Courier New'">proxy</span><span style="color: black; font-family: 宋体">模式做个深入剖析了。我们先来看一个</span><span style="color: black; font-family: 'Courier New'">proxy</span><span style="color: black; font-family: 宋体">模式演变的过程的图示：
<div align="center"><img height="184" alt="" src="http://www.blogjava.net/images/blogjava_net/yeshucheng/clip_image0.jpg" width="463" border="0" /></div>
</span>
<p>&nbsp;</p>
<p style="text-indent: 21pt; text-align: center" align="center"><span style="color: black; font-family: 宋体">图：</span><span style="color: black; font-family: 'Courier New'">RMI</span><span style="color: black; font-family: 宋体">核心结构</span></p>
<p style="text-indent: 21pt"><span style="color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; </span><span style="color: black; font-family: 宋体">我们可以从图示看出从传统的</span><span style="color: black; font-family: 'Courier New'">proxy</span><span style="color: black; font-family: 宋体">模式变化到一个变化的结构有什么不同呢？对于先前我们提出的两个问题就可以很好的做出解释了：</span></p>
<p style="margin-left: 42pt; text-indent: -21pt; tab-stops: list 42.0pt"><span style="color: black; font-family: Wingdings">n<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color: black; font-family: 宋体">既然接口如此简单，那参数又是如何传递过去的呢？</span></p>
<p style="margin-left: 21pt"><span style="color: black; font-family: 'Courier New'">A:</span><span style="color: black; font-family: 宋体">既然是对客户端只开接口暴露，那么我们是就需要一个后台的</span><span style="color: black; font-family: 'Courier New'">socket</span><span style="color: black; font-family: 宋体">来传输接口中已经定义好的参数，通过参数的编组（序列化）方式请求到远程服务上去响应处理。这当中要求定义到对方服务的服务名称和端口号。（这里也就是我们最先提到的那段代码了）</span></p>
<p style="margin-left: 42pt; text-indent: -21pt; tab-stops: list 42.0pt"><span style="color: black; font-family: Wingdings">n<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="color: black; font-family: 宋体">服务端又如何知道我要的是什么呢？</span></p>
<p style="margin-left: 21pt"><span style="color: black; font-family: 'Courier New'">A:ok,</span><span style="color: black; font-family: 宋体">既然客户端是通过</span><span style="color: black; font-family: 'Courier New'">socket</span><span style="color: black; font-family: 宋体">来发送数据，那势必一定需要</span><span style="color: black; font-family: 'Courier New'">ServerSocket</span><span style="color: black; font-family: 宋体">来做这个响应的接收处理了。问题是传过来的参数如何与我们的业务实现类关联上呢？所以这个也就是</span><span style="color: black; font-family: 'Courier New'">skeleton</span><span style="color: black; font-family: 宋体">的职责所在了，在</span><span style="color: black; font-family: 'Courier New'">skeleton</span><span style="color: black; font-family: 宋体">的封装处理中（启动中就把响应实现类给嵌入，聚合实现类），然后通过类转换处理和匹配处理来得到需要响应的结果了。</span></p>
<p><span style="color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; </span></p>
<p align="right"><span style="color: black; font-family: 'Courier New'">&nbsp;&nbsp;&nbsp; </span><span style="color: black; font-family: 宋体">本来说到这想大概有个收尾，但是总觉得还没有把一些问题说透彻。索性想再深入写写。<br />
&nbsp;&nbsp;&nbsp;&nbsp;<a title="从套接字衍生到RMI代码思路" href="http://www.blogjava.net/yeshucheng/archive/2009/02/03/253144.html">从套接字衍生到RMI代码思路</a></span></p>
<img src ="http://www.blogjava.net/yeshucheng/aggbug/252931.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yeshucheng/" target="_blank">叶澍成</a> 2009-02-02 11:57 <a href="http://www.blogjava.net/yeshucheng/archive/2009/02/02/252931.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HashMap原理及冲突之简谈</title><link>http://www.blogjava.net/yeshucheng/archive/2008/09/15/229053.html</link><dc:creator>叶澍成</dc:creator><author>叶澍成</author><pubDate>Mon, 15 Sep 2008 13:53:00 GMT</pubDate><guid>http://www.blogjava.net/yeshucheng/archive/2008/09/15/229053.html</guid><wfw:comment>http://www.blogjava.net/yeshucheng/comments/229053.html</wfw:comment><comments>http://www.blogjava.net/yeshucheng/archive/2008/09/15/229053.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/yeshucheng/comments/commentRss/229053.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yeshucheng/services/trackbacks/229053.html</trackback:ping><description><![CDATA[&nbsp;
<p style="text-indent: 21pt"><span style="font-family: 宋体">了解</span>HashMap<span style="font-family: 宋体">原理对于日后的缓存机制多少有些认识。在网络中也有很多方面的帖子，但是很多都是轻描淡写，很少有把握的比较准确的信息，在这里试着不妨说解一二。</span></p>
<p>&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">对于</span>HashMap<span style="font-family: 宋体">主要以键值</span>(key-value)<span style="font-family: 宋体">的方式来体现，笼统的说就是采用</span>key<span style="font-family: 宋体">值的哈希算法来，外加取余最终获取索引，而这个索引可以认定是一种地址，既而把相应的</span>value<span style="font-family: 宋体">存储在地址指向内容中。这样说或许比较概念化，也可能复述不够清楚，来看列式更加清晰：</span></p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 4pt; border-top: windowtext 0.5pt solid; padding-left: 4pt; background: #d9d9d9; padding-bottom: 1pt; border-left: windowtext 0.5pt solid; padding-top: 1pt; border-bottom: windowtext 0.5pt solid">
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp; hash=key.hashCode();//------------------------1</p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp; index=hash%table.lenth;//table<span style="font-family: 宋体">表示当前对象的长度</span>-----------------------2</p>
</div>
<p><span style="font-family: 宋体">其实最终就是这两个式子决定了值得存储位置。但是以上两个表达式还有欠缺。为什么这么说？例如在</span>key.hashCode()<span style="font-family: 宋体">后可能存在是一个负整数，你会问：是啊，那这个时候怎么办呢？所以在这里就需要进一步加强改造式子</span>2<span style="font-family: 宋体">了，修改后的：</span></p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 4pt; border-top: windowtext 0.5pt solid; padding-left: 4pt; background: #d9d9d9; padding-bottom: 1pt; border-left: windowtext 0.5pt solid; padding-top: 1pt; border-bottom: windowtext 0.5pt solid">
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp; index=<span style="font-family: 宋体">（</span>hash&amp;Ox7FFFFFFF)%table.lenth;</p>
</div>
<p><span style="font-family: 宋体">到这里又迷惑了，为什么上面是这样的呢？对于先前我们谈到在</span>hash<span style="font-family: 宋体">有可能产生负数的情况，这里我们使用当前的</span>hash<span style="font-family: 宋体">做一个&#8220;与&#8221;操作，在这里需要和</span>int<span style="font-family: 宋体">最大的值相&#8220;与&#8221;。这样的话就可以保证数据的统一性，把有符号的数值给&#8220;与&#8221;掉。而一般这里我们把二进制的数值转换成</span>16<span style="font-family: 宋体">进制的就变成了：</span>Ox7FFFFFFF<span style="font-family: 宋体">。（注：与操作的方式为，不同为</span>0<span style="font-family: 宋体">，相同为</span>1<span style="font-family: 宋体">）。而对于</span>hashCode()<span style="font-family: 宋体">的方法一般有：</span></p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 4pt; border-top: windowtext 0.5pt solid; padding-left: 4pt; background: #d9d9d9; padding-bottom: 1pt; border-left: windowtext 0.5pt solid; padding-top: 1pt; border-bottom: windowtext 0.5pt solid">
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">&nbsp;&nbsp;&nbsp;&nbsp; public int hashCode(){</p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int hash=0,offset,len=count;</p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char[]&nbsp;var=value;</p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0;i&lt;len;i++){</p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; h=31*hash+var[offset++];</p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return hash;</p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
</div>
<p style="text-indent: 21pt"><span style="font-family: 宋体">说道这里大家可能会说，到这里算完事了吧。但是你可曾想到如果数据都采用上面的方式，最终得到的可能</span>index<span style="font-family: 宋体">会相同怎么办呢？如果你想到的话，那恭喜你</span>!<span style="font-family: 宋体">又增进一步了，这里就是要说到一个名词：冲突率。是的就是前面说道的一旦</span>index<span style="font-family: 宋体">有相同怎么办？数据又该如何存放呢，而且这个在数据量非常庞大的时候这个基率更大。这里按照算法需要明确的一点：每个键（</span>key<span style="font-family: 宋体">）被散列分布到任何一个数组索引的可能性相同，而且不取决于其它键分布的位置。这句话怎么理解呢？从概率论的角度，也就是说如果</span>key<span style="font-family: 宋体">的个数达到一个极限，每个</span>key<span style="font-family: 宋体">分布的机率都是均等的。更进一步就是：即便</span>key1<span style="font-family: 宋体">不等于</span>key2<span style="font-family: 宋体">也还是可能</span>key1.hashCode()=key2.hashCode()<span style="font-family: 宋体">。</span></p>
<p style="text-indent: 21pt"><span style="font-family: 宋体">对于早期的解决冲突的方法有折叠法（</span>folding)<span style="font-family: 宋体">，例如我们在做系统的时候有时候会采用部门编号附加到某个单据标号后，这里比如产生一个</span>9<span style="font-family: 宋体">～</span>11<span style="font-family: 宋体">位的编码。通过对半折叠做。</span></p>
<p><span style="font-family: 宋体">现在的策略有：</span></p>
<p style="margin-left: 18pt; text-indent: -18pt; tab-stops: list 18.0pt">1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">键式散列</span>&nbsp;</p>
<p style="margin-left: 18pt; text-indent: -18pt; tab-stops: list 18.0pt">2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">开放地址法</span></p>
<p><span style="font-family: 宋体">在了解这两个策略前，我们先定义清楚几个名词解释：</span></p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 4pt; border-top: windowtext 0.5pt solid; padding-left: 4pt; background: #d9d9d9; padding-bottom: 1pt; border-left: windowtext 0.5pt solid; padding-top: 1pt; border-bottom: windowtext 0.5pt solid">
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">threshold[<span style="font-family: 宋体">阀值</span>]<span style="font-family: 宋体">，对象大小的边界值</span>;</p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">loadFactor[<span style="font-family: 宋体">加载因子</span>]=n/m <span style="font-family: 宋体">；其中</span>n<span style="font-family: 宋体">代表对象元素个数，</span>m<span style="font-family: 宋体">表示当前表的容积最大值</span></p>
<p style="border-right: medium none; padding-right: 0cm; border-top: medium none; padding-left: 0cm; padding-bottom: 0cm; border-left: medium none; padding-top: 0cm; border-bottom: medium none">threshold=(int)table.length*loadFactor</p>
</div>
<p><span style="font-family: 宋体">清晰了这几个定义，我们再来看具体的解决方式</span></p>
<p><span style="font-family: 宋体">键式散列：</span></p>
<p style="text-indent: 27pt"><span style="font-family: 宋体">我们直接看一个实例，这样就更加清晰它的工作方式，从而避免文字定义。我们这里还是来举一个图书编号的例子，下面比如有这样一些编号：</span></p>
<p style="text-indent: 27pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: black">78938</span><span style="color: black">-000</span><span style="color: black">0</span></p>
<p style="text-indent: 27pt"><span style="color: black">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>45678-0001</p>
<p style="text-indent: 27pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 72678-0002</p>
<p style="text-indent: 27pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 24678-0001</p>
<p style="text-indent: 27pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;16678-0001</p>
<p style="text-indent: 27pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 98678-0003</p>
<p style="text-indent: 27pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 85678-0002</p>
<p style="text-indent: 27pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 45232-0004</p>
<p><span style="font-family: 宋体">步骤：</span></p>
<p style="margin-left: 18pt; text-indent: -18pt; tab-stops: list 18.0pt">1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">把编号作为</span>key,<span style="font-family: 宋体">即：</span>int hash=key.hashCode();</p>
<p style="margin-left: 18pt; text-indent: -18pt; tab-stops: list 18.0pt">2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>int index=hash%<span style="font-family: 宋体">表大小；</span></p>
<p style="margin-left: 18pt; text-indent: -18pt; tab-stops: list 18.0pt">3.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">逐步按顺序插入对象中</span></p>
<p><span style="font-family: 宋体">现在问题出现了：对于编号通过散列算法后很可能产生相同的索引值，意味着存在冲突。</span></p>
<p style="text-align: center" align="center"><img height="436" alt="" src="http://www.blogjava.net/images/blogjava_net/yeshucheng/111.JPG" width="617" border="0" /></p>
<p><span style="font-family: 宋体">解释上面的操作：如果对于</span>key.hashCode()<span style="font-family: 宋体">产生了冲突（比如途中对于插入</span>24678-0001<span style="font-family: 宋体">对于通过哈希算法后可能产生的</span>index<span style="font-family: 宋体">或许也是</span>501<span style="font-family: 宋体">），既而把相应的前驱有相同的</span>index<span style="font-family: 宋体">的对象指向当前引用。这也就是大家认定的单链表方式。以此类推</span>&#8230;</p>
<p><span style="font-family: 宋体">而这里存在冲突对象的元素放在</span>Entry<span style="font-family: 宋体">对象中，</span>Entry<span style="font-family: 宋体">具有以下一些属性：</span></p>
<p>int hash;</p>
<p>Object key;</p>
<p>Entry next;</p>
<p><span style="font-family: 宋体">对于</span>Entry<span style="font-family: 宋体">对象就可以直接追溯到链表数据结构体中查阅。</span></p>
<p><span style="font-family: 宋体">开放地址法：</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; tab-stops: list 21.0pt">1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">线性地址探测法：</span></p>
<p><span style="font-family: 宋体">如何理解这个概念呢，一句话：就是通过算法规则在对象地址</span>N+1<span style="font-family: 宋体">中查阅找到为</span>NULL<span style="font-family: 宋体">的索引内容。</span></p>
<p><span style="font-family: 宋体">处理方式：如果</span>index<span style="font-family: 宋体">索引与当前的</span>index<span style="font-family: 宋体">有冲突，即把当前的索引</span>index+1<span style="font-family: 宋体">。如果在</span>index+1<span style="font-family: 宋体">已经存在占位现象（</span>index+1<span style="font-family: 宋体">的内容不为</span>NULL<span style="font-family: 宋体">）试图接着</span>index+2<span style="font-family: 宋体">执行。。。直到找到索引为内容为</span>NULL<span style="font-family: 宋体">的为止。这种处理方式也叫：线性地址探测法</span>(offset-of-1)</p>
<p><span style="font-family: 宋体">如果采用线性地址探测法会带来一个效率的不良影响。现在我们来分析这种方式会带来哪些不良因素。大家试想下如果一个非常庞大的数据存储在</span>Map<span style="font-family: 宋体">中，假如在某些记录集中有一些数据非常相似（他们产生的索引在内存的某个块中非常的密集），也就是说他们产生的索引地址是一个连续数值，而造成数据成块现象。另一个致命的问题就是在数据删除后，如果再次查询可能无法定到下一个连续数字，这个又是一个什么概念呢？例如以下图片就很好的说明开发地址散列如何把数据按照算法插入到对象中：</span></p>
<p style="text-align: center" align="center"><img height="502" alt="" src="http://www.blogjava.net/images/blogjava_net/yeshucheng/222.JPG" width="512" border="0" /></p>
<p><span style="font-family: 宋体">对于上图的注释步骤说明：</span></p>
<p style="line-height: 119%; text-align: center" align="center"><span style="font-family: 宋体">从数据&#8220;</span>78938-0000<span style="font-family: 宋体">&#8221;开始通过哈希算法按顺序依次插入到对象中，例如</span>78938-0000<span style="font-family: 宋体">通过换</span></p>
<p style="line-height: 119%"><span style="font-family: 宋体">算得到索引为</span>0<span style="font-family: 宋体">，当前所指内容为</span>NULL<span style="font-family: 宋体">所以直接插入；</span><span style="color: black">45678-0001</span><span style="color: black; font-family: 宋体">同样通过换算得到索引为地址</span><span style="color: black">501</span><span style="color: black; font-family: 宋体">所指内容，当前内容为</span><span style="color: black">NULL</span><span style="color: black; font-family: 宋体">所以也可以插入；</span><span style="color: black">72678-0002</span><span style="color: black; font-family: 宋体">得到索引</span><span style="color: black">502</span><span style="color: black; font-family: 宋体">所指内容，当前内容为</span><span style="color: black">NULL</span><span style="color: black; font-family: 宋体">也可以插入；请注意当</span><span style="color: black">24678-0001</span><span style="color: black; font-family: 宋体">得到索引也为</span><span style="color: black">501</span><span style="color: black; font-family: 宋体">，当前地址所指内容为</span><span style="color: black">45678-0001</span><span style="color: black; font-family: 宋体">。即表示当前数据存在冲突，则直接对地址</span><span style="color: black">501+1=502</span><span style="color: black; font-family: 宋体">所指向内容为</span><span style="color: black">72678-0002</span><span style="color: black; font-family: 宋体">不为</span><span style="color: black">NULL</span><span style="color: black; font-family: 宋体">也不允许插入，再次对索引</span><span style="color: black">502+1=503</span><span style="color: black; font-family: 宋体">所指内容为</span><span style="color: black">NULL</span><span style="color: black; font-family: 宋体">允许插入。。。依次类推只要对于索引存在冲突现象，则逐次下移位知道索引地址所指为</span><span style="color: black">NULL</span><span style="color: black; font-family: 宋体">；如果索引不冲突则还是按照算法放入内容。对于这样的对象是一种插入方式，接下来就是我们的删除</span><span style="color: black">(remove)</span><span style="color: black; font-family: 宋体">方法了。按照常理对于删除，方式基本区别不大。但是现在问题又出现了，如果删除的某个数据是一个存在冲突索引的内容，带来后续的问题又会接踵而来。那是什么问题呢？我们还是同样来看看图示的描述，对于图</span><span style="color: black">-2</span><span style="color: black; font-family: 宋体">中如果删除</span><span style="color: black">(remove)</span><span style="color: black; font-family: 宋体">数据</span><span style="color: black">24678-0001</span><span style="color: black; font-family: 宋体">的方法如下图所示：</span></p>
<p style="line-height: 119%; text-align: center" align="center"><img height="502" alt="" src="http://www.blogjava.net/images/blogjava_net/yeshucheng/333.JPG" width="512" border="0" /></p>
<p style="line-height: 119%"><span style="font-family: 宋体">对于我们会想当然的觉得只要把指向数据置为</span>NULL<span style="font-family: 宋体">就可以</span>,<span style="font-family: 宋体">这样的做法对于删除来说当然是没有问题的。如果再次定位检索数据</span>16678-0001<span style="font-family: 宋体">不会成功，因为这个时候以前的链路已经堵上了，但是需要检索的数据事实上又存在。那我们如何来解决这个问题呢？对于</span>JDK<span style="font-family: 宋体">中的</span>Entry<span style="font-family: 宋体">类中的方法存在一个：</span>boolean markedForRemoval;<span style="font-family: 宋体">它就是一个典型的删除标志位，对于对象中如果需要删除时，我们只是对于它做一个&#8220;软删除&#8221;即置一个标志位为</span>true<span style="font-family: 宋体">就可以。而插入时，默认状态为</span>false<span style="font-family: 宋体">就可以。这样的话就变成以下图所示：</span></p>
<p style="line-height: 119%; text-align: center" align="center"><img height="502" alt="" src="http://www.blogjava.net/images/blogjava_net/yeshucheng/444.JPG" width="512" border="0" /></p>
<p style="line-height: 119%"><span style="font-family: 宋体">通过以上方式更好的解决冲突地址删除数据无法检索其他链路数据问题了。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt; line-height: 119%; tab-stops: list 21.0pt">2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">双散列（余商法）</span></p>
<p style="margin-left: 21pt; text-indent: 21pt; line-height: 119%"><span style="font-family: 宋体">在了解开放地址散列的时候我们一直在说解决方法，但是大家都知道一个数据结构的完善更多的是需要高效的算法。这当中我们却没有涉及到。接下来我们就来看看在开放地址散列中它存在的一些不足以及如何改善这样的方法，既而达到无论是在方法的解决上还是在算法的复杂度上更加达到高效的方案。</span></p>
<p style="margin-left: 21pt; text-indent: 21pt; line-height: 119%"><span style="font-family: 宋体">在图</span>2-1<span style="font-family: 宋体">中类似这样一些数据插入进对象，存在冲突采用不断移位加一的方式，直到找到不为</span>NULL<span style="font-family: 宋体">内容的索引地址。也正是由于这样一种可能加大了时间上的变慢。大家是否注意到像图这样一些数据目前呈现出一种连续索引的插入，而且是一种成块是的数据。如果数据量非常的庞大，或许这种可能性更大。尽管它解决了冲突，但是对于数据检索的时间度来说，我们是不敢想象的。所有分布到同一个索引</span>index<span style="font-family: 宋体">上的</span>key<span style="font-family: 宋体">保持相同的路径：</span>index,index+1,index+2&#8230;<span style="font-family: 宋体">依此类推。更加糟糕的是索引键值的检索需要从索引开始查找。正是这样的原因，对于线性探索法我们需要更进一步的改进。而刚才所描述这种成块出现的数据也就定义成：簇。而这样一种现象称之为：主簇现象。</span></p>
<p style="line-height: 119%"><span style="font-family: 宋体">（主簇：就是冲突处理允许簇加速增长时出现的现象）而开放式地址冲突也是允许主簇现象产生的。那我们如何来避免这种主簇现象呢？这个方式就是我们要来说明的：双散列解决冲突法了。主要的方式为：</span></p>
<p style="background: #e5e5e5; margin-left: 21pt; text-indent: -21pt; line-height: 119%; tab-stops: list 21.0pt"><span style="font-family: Wingdings">u<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>int hash=key.hasCode();</p>
<p style="background: #e5e5e5; margin-left: 21pt; text-indent: -21pt; line-height: 119%; tab-stops: list 21.0pt"><span style="font-family: Wingdings">u<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>int index=(hash&amp;Ox7FFFFFFF)%table.length;</p>
<p style="background: #e5e5e5; margin-left: 21pt; text-indent: -21pt; line-height: 119%; tab-stops: list 21.0pt"><span style="font-family: Wingdings">u<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">按照以上方式得到索引存在冲突，则开始对当前索引移位，而移位方式为：</span></p>
<p style="background: #e5e5e5; line-height: 119%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; offset=(hash&amp;Ox7FFFFFFF)/table.length;</p>
<p style="background: #e5e5e5; margin-left: 21pt; text-indent: -21pt; line-height: 119%; tab-stops: list 21.0pt"><span style="font-family: Wingdings">u<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">如果第一次移位还存在同样的冲突，则继续：当前冲突索引位置（索引号</span>+<span style="font-family: 宋体">余数）</span>%<span style="font-family: 宋体">表</span>.length</p>
<p style="background: #e5e5e5; margin-left: 21pt; text-indent: -21pt; line-height: 119%; tab-stops: list 21.0pt"><span style="font-family: Wingdings">u<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体">如果存在的余数恰好是表的倍数，则作偏移位置为一下移，依此类推</span></p>
<p style="text-indent: 21pt; line-height: 119%"><span style="font-family: 宋体">这样双散列冲突处理就避免了主簇现象。至于</span>HashSet<span style="font-family: 宋体">的原理基本和它是一致的，这里不再复述。在这里其实还是主要说了一些简单的解决方式，而且都是在一些具体参数满足条件下的说明，像一旦数据超过初始值该需要</span>rehash<span style="font-family: 宋体">，加载因子一旦大于</span>1.0<span style="font-family: 宋体">是何种情况等等。还有很多问题都可以值得我们更加进一步讨论的，比如：在</span>java.util.HashMap<span style="font-family: 宋体">中的加载因子为什么会是</span>0.75<span style="font-family: 宋体">，而它默认的初始大小为什么又是</span>16<span style="font-family: 宋体">等等这些问题都还值得说明。要说明这些问题可能又需要更加详尽的说明清楚。</span></p>
<img src ="http://www.blogjava.net/yeshucheng/aggbug/229053.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yeshucheng/" target="_blank">叶澍成</a> 2008-09-15 21:53 <a href="http://www.blogjava.net/yeshucheng/archive/2008/09/15/229053.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>