<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>kafka0102的边城客栈 &#187; java</title>
	<atom:link href="http://www.kafka0102.com/tag/java/feed" rel="self" type="application/rss+xml" />
	<link>http://www.kafka0102.com</link>
	<description>要有最朴素的生活与最遥远的梦想，即使明日天寒地冻、路远马亡。</description>
	<lastBuildDate>Sat, 18 Jun 2011 04:20:42 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Double.NaN != Double.NaN</title>
		<link>http://www.kafka0102.com/2011/05/439.html</link>
		<comments>http://www.kafka0102.com/2011/05/439.html#comments</comments>
		<pubDate>Fri, 20 May 2011 09:43:11 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[double.nan]]></category>
		<category><![CDATA[nan]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=439</guid>
		<description><![CDATA[昨天做数据时发现个很诡异的情况，当然，再诡异的技术现象也有起发生原因。抛开我的问题来说，我可以再提出个问题：是否在某种编程语言中，存在着那么一个变量i，使得i!=i成立，也使得while(i==i);可以成功的退出？如果你想到并理解了，你可以终止阅读这篇可能冗长的文章，尽管为了填补这个月的博客空白我刻意小题大作一番。在java语言中，Double.NaN就能使得上面两个表达式成立。]]></description>
			<content:encoded><![CDATA[<p>昨天做数据时发现个很诡异的情况，当然，再诡异的技术现象也有发生原因。抛开我的问题来说，我可以再提出个问题：是否在某种编程语言中，存在着那么一个变量i，使得i!=i成立，也使得while(i==i);可以成功的退出？如果你想到并理解了，你可以终止阅读这篇可能冗长的文章，尽管为了填补这个月的博客空白我刻意小题大作一番。在java语言中，Double.NaN就能使得上面两个表达式成立。</p>
<p>说起浮点型中的NaN，之前的少有印象就是来自javascript，而考虑到没怎么搞过js，这点印象也就仅限于曾经alert出来的令人惊异的NaN（以及undefined）了。先说说浮点型吧，它的标准出自<a href="http://en.wikipedia.org/wiki/IEEE_754-2008" target="blank">IEEE 754</a>，Java规范中的章节是<a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.3">http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.3</a>，两篇也挺冗长的英文内容。可以重点提及的是，在内部实现上，32位的float和64位的double是使用int和long表示的。具体的表示方法可以从java api文档上看到更好的解释。以Double为例，它提供了下面3个方法：</p>
<p style="text-align: center;"><a href="http://www.kafka0102.com/wp-content/uploads/2011/05/Screenshot.png"><img class="aligncenter size-full wp-image-445" title=" doubletolong" src="http://www.kafka0102.com/wp-content/uploads/2011/05/Screenshot.png" alt="" width="576" height="370" /></a></p>
<p style="text-align: center;"><a href="http://www.kafka0102.com/wp-content/uploads/2011/05/Screenshot-1.png"><img class="aligncenter size-full wp-image-446" title="doubletorawlong" src="http://www.kafka0102.com/wp-content/uploads/2011/05/Screenshot-1.png" alt="" width="577" height="428" /></a></p>
<p style="text-align: center;"><a href="http://www.kafka0102.com/wp-content/uploads/2011/05/Screenshot-2.png"><img class="aligncenter size-full wp-image-447" title="longtodouble" src="http://www.kafka0102.com/wp-content/uploads/2011/05/Screenshot-2.png" alt="" width="631" height="446" /></a></p>
<p>分析发现，除了常规的double取值，NaN（not a number）并不是对应着唯一的表示，尽管它并不是一个数值，比如除0或者对负数取平方根的结果都是NaN，但它们的发生原因是不一样的，所以如果是signaling NaN，可以通过比对位来得到更多的信息，尽管这在多数语言（包括Java）中是不可见的。那么，我们来看看Double.NaN会带来什么特别之处吧：</p>
<p>1）Double.NaN != Double.NaN。既非数值，何来相等。和Double.NaN相关的比较操作结果都是false，所以，Double.NaN &gt; 1.0为false，Double.NaN &lt; 1.0为false，Double.NaN == 1.0也为false。不过，Double a = new Double(Double.NaN);a.equals(a)==true;是成立的，因为对象a比较的是引用而不是数值。</p>
<p>2）Double.NaN + Double.NaN  -&gt;  Double.NaN<br />
3）Double.NaN + 1.0  -&gt;  Double.NaN<br />
4）(int) (Double.NaN) -&gt; 0。我的问题也是因为这个转换，以致我不可思议的盯着那些本不应该为0的结果。</p>
<p>从上可以看出，在Double.NaN存在时，既有的逻辑判断和数值运算可能走向未料想的方向。从语言设计角度来说，Java接纳了浮点型规范中的NaN，不像整形那样抛出异常，但这却带来潜伏的bug陷阱。看看其它语言的做法吧，C/C++会毫不留情的出core，ruby、python会报错，即便是一塌糊涂的PHP，至少还会报个warning，是不是Java的表弟C#有可能接纳了NaN？要我说啊，还是抛个异常好些，既非数值，要你添个毛乱阿。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2011/05/439.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>httpclient的并发连接问题</title>
		<link>http://www.kafka0102.com/2010/11/405.html</link>
		<comments>http://www.kafka0102.com/2010/11/405.html#comments</comments>
		<pubDate>Fri, 19 Nov 2010 17:56:18 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[httpclient]]></category>
		<category><![CDATA[solr]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=405</guid>
		<description><![CDATA[	昨天的搜索系统又出状况了，几个库同时重建索引变得死慢。经过一个上午的复现分析，确定问题出现httpclient的使用上。搜索系统在重建索引时，是并发多个线程（默认是8个）不停的从PHP客户端取数据（当然，从另一个角度来说，搜索系统是客户端，PHP端是服务端），取回后放到一个队列里由单独的一个线程更新索引。在测试环境复现发现，对于一个请求，PHP端打印耗时是1-2秒，但搜索端打印在4-6秒。这种耗时差别也就两种可能性，一个是PHP端返回到搜索端接受完耗时太长，另一个就是搜索端在真正发给PHP端数据前等待了很久。因为有了之前的jetty7的困顿，起初我怀疑是传输数据的问题。因为请求数据的代码部分我只是简单的使用了httpclient，所以只能从httpclient着手分析。我想到把PHP端和搜索端的请求起始和结束时间都打出来对照一下，不过在这样做之前我把搜索端的并发请求线程数调到了1,看下单线程情况下效果如何，结果惊奇地发现PHP端和搜索端的耗时相近。所以，可以确定，是httpclient的并发连接处理上可能存在问题。]]></description>
			<content:encoded><![CDATA[<p>	昨天的搜索系统又出状况了，几个库同时重建索引变得死慢。经过一个上午的复现分析，确定问题出现httpclient的使用上（我使用的是3.1这个被广泛使用的遗留版本）。搜索系统在重建索引时，是并发多个线程（默认是8个）不停的从PHP客户端取数据（当然，从另一个角度来说，搜索系统是客户端，PHP端是服务端），取回后放到一个队列里由单独的一个或多个线程更新索引。在测试环境复现发现，对于一个请求，PHP端打印耗时是1-2秒，但搜索端打印在4-6秒。这种耗时差别也就两种可能性，一个是PHP端返回到搜索端接受完耗时太长，另一个就是搜索端在真正发给PHP端数据前等待了很久。因为有了之前的jetty7的困顿，起初我怀疑是传输数据的问题。因为请求数据的代码部分我只是简单的使用了httpclient，所以只能从httpclient着手分析。我想到把PHP端和搜索端的请求起始和结束时间都打出来对照一下，不过在这样做之前我把搜索端的并发请求线程数调到了1,看下单线程情况下效果如何，结果惊奇地发现PHP端和搜索端的耗时相近。所以，可以确定，是httpclient的并发连接处理上可能存在问题。不消说，翻开httpclient API中和配置相关的接口，结果找到HttpConnectionManagerParams类中下面两个函数：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setDefaultMaxConnectionsPerHost<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> maxHostConnections<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setMaxTotalConnections<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> maxTotalConnections<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>	httpclient在处理请求连接方面使用了连接池，它内部实际上有两种连接池，一种是全局的ConnectionPool，一种是每主机（per-host）HostConnectionPool。参数maxHostConnections就HostConnectionPool中表示每主机可保持连接的连接数，maxTotalConnections是ConnectionPool中可最多保持的连接数。每主机的配置类是HostConfiguration，HttpClient有个int executeMethod(final HostConfiguration hostConfiguration, final HttpMethod method)方法可以指定使用哪个HostConfiguration，不过多数情况都是不显示指定HostConfiguration，这样httpclient就用了默认的HostConfiguration=null，也就是说所有的请求可以认为指自同一个主机。如果不设置这两个参数，httpclient自然会用默认的配置，也就是MultiThreadedHttpConnectionManager中的：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #008000; font-style: italic; font-weight: bold;">/** The default maximum number of connections allowed per host */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> DEFAULT_MAX_HOST_CONNECTIONS <span style="color: #339933;">=</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span>   <span style="color: #666666; font-style: italic;">// Per RFC 2616 sec 8.1.4</span>
&nbsp;
    <span style="color: #008000; font-style: italic; font-weight: bold;">/** The default maximum number of connections allowed overall */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> DEFAULT_MAX_TOTAL_CONNECTIONS <span style="color: #339933;">=</span> <span style="color: #cc66cc;">20</span><span style="color: #339933;">;</span></pre></div></div>

<p>    默认的maxHostConnections大小只有2,也就是说，在我并发8个线程请求数据时，实际上会有6个线程处于等待被调度,这也就解释上面的现象了。再看看上面的注释，我从http://www.faqs.org/rfcs/rfc2616.html找到从了RFC 2616 sec 8.1.4  Practical Considerations段落的最后一段：<br />
<font color="blue"><br />
       Clients that use persistent connections SHOULD limit the number of simultaneous connections that they maintain to a given server. A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy. A proxy SHOULD use up to 2*N connections to  another server or proxy, where N is the number of simultaneously active users. These guidelines are intended to improve HTTP response times and avoid congestion.<br />
</font><br />
	看这叙述，也就表明人家httpclient设置maxHostConnections为2是有根有据的。不过，这种设置显然适合的是浏览器这种客户端，但我相信，多数使用httpclient并不希望有这种默认的限制。而它默认的只有20的maxTotalConnections也太有些吝啬了。我后来浏览solr的客户端server类CommonsHttpSolrServer的代码发现了下面的段落，solr要比我更了解httpclient：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    _httpClient <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>client <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">?</span> <span style="color: #000000; font-weight: bold;">new</span> HttpClient<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> MultiThreadedHttpConnectionManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">:</span> client<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>client <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #666666; font-style: italic;">// set some better defaults if we created a new connection manager and client</span>
      <span style="color: #666666; font-style: italic;">// increase the default connections</span>
      <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">setDefaultMaxConnectionsPerHost</span><span style="color: #009900;">&#40;</span> <span style="color: #cc66cc;">32</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  <span style="color: #666666; font-style: italic;">// 2</span>
      <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">setMaxTotalConnections</span><span style="color: #009900;">&#40;</span> <span style="color: #cc66cc;">128</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// 20</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>    对于httpclient，特别指出的是它的MultiThreadedHttpConnectionManager，看名字好像是多线程并发请求似的，其实不是，但它也确实用到了多线程，那是在发现连接不够用时起个等待线程wait信号，这个名称的含义应该是多线程情况线程安全的HttpConnectionManager。<br />
    使用httpclient还有两点经验，一个是创建的MultiThreadedHttpConnectionManager 实例最好是全局的，否则会有多个连接池，而HttpClient是线程安全的，可以多个实例。另一个是，在处理请求的最后，也就是finnaly里中，要调用method.releaseConnection();回收连接，否则连接池就可能会爆了。</p>
<p>补充：写完之后倒在床上，我又想起了几个问题，这里补充上：<br />
1、系统原先重建索引隐约记得速度还是可以的，为什么现在变慢得如此明显？这有两方面的原因，一个是原来系统取数据是用的单线程（我后来发现单取数据取数据速度跟不上更新索引的速度所以改成多线程），另一个是，当时重建没有一下子同时开启数个库。所以，即便是同样的代码，环境变了，效果也可能变了。当这种改变悄然发生了，程序员却没有捕捉到，才会第一直觉感到问题的诡异。<br />
2、对于长时间不能获得连接的情况，httpclient是否有warn日志报出来？因为我使用了httpclient的getResponseBodyAsStream方法，而它会打出warn日志，所以我是关掉了httpclient的warn级别的。所以，我又检查了httpclient的代码，可惜没看到相关warning log，这点httpclient可以改进下。不过httpclient现在都是4时代了，而我使用的还是3.1的，而3.x已经被停止更新了，所以再采用httpclient可以考虑4版本的，尽管现在能见到的代码几乎都是用的3.x系列的。<br />
3、httpclient的文档是否有特别提到连接数配置的情况？我翻看了一下，确实在关于threading一页中有提到。不过，我等使用它时显然没有完整阅毕它的文档。或许，httpclient给出个明显的最佳实践到能引起使用者的注意，否则误用的情况还是会时有发生。不信，google之。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/11/405.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>各种java序列化工具性能对比</title>
		<link>http://www.kafka0102.com/2010/10/383.html</link>
		<comments>http://www.kafka0102.com/2010/10/383.html#comments</comments>
		<pubDate>Sun, 24 Oct 2010 10:58:42 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[序列化]]></category>
		<category><![CDATA[评测]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=383</guid>
		<description><![CDATA[看到一个很不错的工具http://github.com/eishay/jvm-serializers/，可以用它来评测各种流行的java序列化反序列化工具的性能，使用上也很简单。想试试该工具的，下载源码后参考起README操作即可。而我更关心的是，是各种工具的性能对比，以作选择的一个衡量标准，也就是http://github.com/eishay/jvm-serializers/wiki的图示和数据。本文也就简单转摘其图示，图示中的java-manual指的是根据对象（数据）格式手工操作（当然是最快的，但不具有通用性），java- buildin-in就是内置的序列化方式（ObjectOutputStream、ObjectInputStream），其他工具的使用版本可以查看其wiki。]]></description>
			<content:encoded><![CDATA[<p>看到一个很不错的工具<a href="http://github.com/eishay/jvm-serializers/" target="_blank">http://github.com/eishay/jvm-serializers/</a>，可以用它来评测各种流行的java序列化反序列化工具，使用上也很简单。想试试该工具的，下载源码后参考起README操作即可。而我更关心的是，是各种工具的性能对比，以作选择的一个衡量标准，也就是<a href="http://github.com/eishay/jvm-serializers/wiki" target="_blank">http://github.com/eishay/jvm-serializers/wiki</a>的图示和数据。本文也就简单转摘其图示，图示中的java-manual指的是根据对象（数据）格式手工操作（当然是最快的，但不具有通用性），java-buildin-in就是内置的序列化方式（ObjectOutputStream、ObjectInputStream），其他工具的使用版本可以查看其wiki。</p>
<h2>1、Total Time (“total”)</h2>
<p>创建一个对象，将其序列化成一个字节数组，然后再反序列化成一个对象。</p>
<p><a href="http://www.kafka0102.com/wp-content/uploads/2010/10/chart1.png"><img class="alignleft size-full wp-image-384" title="chart1" src="http://www.kafka0102.com/wp-content/uploads/2010/10/chart1.png" alt="" width="700" height="402" /></a></p>
<h2>2、Serialization Time (“ser”)</h2>
<p>创建一个对象，将其序列化成一个字节数组。</p>
<p><a href="http://www.kafka0102.com/wp-content/uploads/2010/10/chart2.png"><img class="alignleft size-full wp-image-385" title="chart2" src="http://www.kafka0102.com/wp-content/uploads/2010/10/chart2.png" alt="" width="700" height="402" /></a></p>
<h2>3、Deserialization Time (“deser+deep”)</h2>
<p>相比于序列化，反序列化更耗时。为了更公平的比较，jvm-serializers在反序列化测试时访问了反序列化得到的对象的所有字段（也就是deep的含义），因为部分工具反序列化时“偷懒”而没有做足工作。</p>
<p><a href="http://www.kafka0102.com/wp-content/uploads/2010/10/chart3.png"><img class="alignleft size-full wp-image-386" title="chart3" src="http://www.kafka0102.com/wp-content/uploads/2010/10/chart3.png" alt="" width="700" height="402" /></a></p>
<h2>4、Serialized Size (“size”)</h2>
<p>序列化数据的大小，这个大小会依赖于使用的数据。</p>
<p><a href="http://www.kafka0102.com/wp-content/uploads/2010/10/chart4.png"><img class="alignleft size-full wp-image-387" title="chart4" src="http://www.kafka0102.com/wp-content/uploads/2010/10/chart4.png" alt="" width="700" height="402" /></a></p>
<h2>5、Serialization Compressed Size (“size+dfl”)</h2>
<p>使用java内置的DEFLATE(zlib)压缩的序列化数据的大小。</p>
<p><a href="http://www.kafka0102.com/wp-content/uploads/2010/10/chart5.png"><img class="alignleft size-full wp-image-388" title="chart5" src="http://www.kafka0102.com/wp-content/uploads/2010/10/chart5.png" alt="" width="700" height="402" /></a></p>
<h2>6、Object Creation Time (“create”)</h2>
<p>对象创建耗时很短（平均100纳秒）所以通常的比较没什么意义。不过，不同工具创建的对象在表现上会有不同。有的工具只是创建普通的java类，你可以直接访问其字段，而有的使用get/set方法，有的使用builder模式。<br />
<a href="http://www.kafka0102.com/wp-content/uploads/2010/10/chart6.png"><img class="alignleft size-full wp-image-389" title="chart6" src="http://www.kafka0102.com/wp-content/uploads/2010/10/chart6.png" alt="" width="700" height="402" /></a></p>
<p>分析这些对比，java内置的序列化方式性能很差（这才催生了各种序列化工具）。在这些工具中，protostuff表现极为出色，盖过了名头响亮的protobuff和thrift。通用格式中，json要比xml强不少，而不同工具对同样格式的性能表现也有差别，这也给了选择工具的一个指导。另一个值得一提的是bson，尽管jvm-serializers没有包含它，相信性能上应该不错。也可以参考jvm-serializers已有工具评测代码的实现，添加比如处理bson、php等格式的序列化工具的评测。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/10/383.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Is Terracotta&#8217;s BigMemory a big thing?</title>
		<link>http://www.kafka0102.com/2010/09/343.html</link>
		<comments>http://www.kafka0102.com/2010/09/343.html#comments</comments>
		<pubDate>Thu, 30 Sep 2010 09:40:11 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[BigMemory]]></category>
		<category><![CDATA[ehcache]]></category>
		<category><![CDATA[jvm]]></category>
		<category><![CDATA[terracotta]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=343</guid>
		<description><![CDATA[Terracotta最近推出了个新东西--BigMemory，使得Infoq上的这篇Terracotta's BigMemory Aiming to Eliminate Garbage Collection for Java Caches文章引来长长的争论。像GigaSpaces、Infinispan等和Terracotta有竞争关系的商业或开源的对手，对BigMemory的诸多方面提出了疑问和质疑。如果BigMemory真的如Terracotta吹的那般好，那些竞争对手该情何以堪？就算它真的好，也要挑出它的不是，比如就有评论说现在都分布式年代了，还搞什么单JVM实例优化？暂且放下这些争论，看看BigMemory是个怎样的东西，值得大家如此大动神经。]]></description>
			<content:encoded><![CDATA[<p>Terracotta最近推出了个新东西&#8211;BigMemory，使得Infoq上的这篇<a href="http://www.infoq.com/news/2010/09/bigmemory " target="_blank">Terracotta&#8217;s BigMemory Aiming to Eliminate Garbage Collection for Java Caches</a>文章引来长长的争论。像GigaSpaces、Infinispan等和Terracotta有竞争关系的商业或开源的对手，对BigMemory的诸多方面提出了疑问和质疑。如果BigMemory真的如Terracotta吹的那般好，那些竞争对手该情何以堪？就算它真的好，也要挑出它的不是，比如就有评论说现在都分布式年代了，还搞什么单JVM实例优化？暂且放下这些争论，看看BigMemory是个怎样的东西，值得大家如此大动神经。</p>
<p>JVM GC的问题可以说是“臭名昭著”，尽管现在一台服务器的内存可以动辄几十G到上百G，但单个JVM实例并不能充分利用硬件提供的内存资源，因为JVM内存容量越大，由GC带来的应用“暂停”现象就越明显。所以，通常单个JVM实例的内存容量要控制在一定范围内。这也使得，为了能有效利用机器的内存，一台机器会部署多个JVM实例。而对于需要大规模内存的Java应用，比如Cache系统，想不分布式都不行。</p>
<p>但Terracotta说了，他们的大多数客户并不需要分布式的Cache系统，单个Ehcache实例就够用了，只是客户们希望单个Ehcache实例能支持更大的内存容量，并且不要有性能问题。所以，BigMemory被创造出来了。BigMemory不是在JVM堆上分配内存的（off heap），内存的分配与回收不受GC控制，容量方面可以达到物理内存规模。因为BigMemory不是开源的，Terracotta没有透露出BigMemory的实现原理，但其<a href="http://ehcache.org/documentation/offheap_store.html" target="_blank">使用文档</a>指出，使用BigMemory需要配置MaxDirectMemorySize选项，并且其是100%Java开发的，所以BigMemory应该是基于DirectBuffer的。至于BigMemory的技术难度和复杂性，我还不好揣测，是不是通过DirectBuffer分配了一块大的ByteArray，然后有一套有效的堆外内存管理机制呢？</p>
<p>说说BigMemory的效果吧。以Ehcache为例，它原来支持两层store，即MemStore和DiskStore，MemStore的大小受限于GC影响，一般控制在（4G？,我有些记不清了，它的文档应该有说明的）以下为好；而DiskStore相比于MemStore，性能方面有百倍的差距，更适合做个备份。现在引入BigMemory后，Ehcache的Stroe就有三层：MemStore可以控制在较好的规模（比如2G），使得GC不会对应用服务产生严重的影响，并且能cache住大多数热的内容；BigMemory可以给出更大的容量，cache那些不是很热的内容，因为BigMemory保存的是对象序列化后的内容，所以对BigMemory管理的对象操作有个序列化和反序列化过程，使得BigMemory相比MemStore会有10倍左右的性能损失，但相比于分布式的cache读取，这些性能损失是已经很小了；而DiskStore，它就真的适合做个备份，以提升应用重启动时间。</p>
<p><a href="http://www.kafka0102.com/wp-content/uploads/2010/09/tiered_storage.png"><img class="aligncenter size-full wp-image-344" title="tiered_storage" src="http://www.kafka0102.com/wp-content/uploads/2010/09/tiered_storage.png" alt="" width="493" height="243" /></a></p>
<p>如果Terracotta给出的数据和评测准确，我觉得BigMemory是个很不错的东西。即便是应用的分布式化盛行，但提升单个JVM的内存使用效果对很多场景还是很有价值的，君不见还有大公司热衷于mysql的单机优化吗？不知道是否会有有心人做出个通用的开源的BigMemory出来，甚至集成到JDK中，以造福Javaer们呢？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/09/343.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>HttpClient的“Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.”警告释疑</title>
		<link>http://www.kafka0102.com/2010/08/316.html</link>
		<comments>http://www.kafka0102.com/2010/08/316.html#comments</comments>
		<pubDate>Sat, 21 Aug 2010 07:43:19 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[httpclient]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=316</guid>
		<description><![CDATA[使用HttpClient，总是报出“Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.”的WARN日志，定位到HttpClient的源码如下：

    public byte&#91;&#93; getResponseBody&#40;&#41; throws IOException &#123;
        if &#40;this.responseBody == null&#41; &#123;
            InputStream instream = getResponseBodyAsStream&#40;&#41;;
     [...]]]></description>
			<content:encoded><![CDATA[<p>使用HttpClient，总是报出“Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.”的WARN日志，定位到HttpClient的源码如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> getResponseBody<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">IOException</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">responseBody</span> <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #003399;">InputStream</span> instream <span style="color: #339933;">=</span> getResponseBodyAsStream<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>instream <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #000066; font-weight: bold;">long</span> contentLength <span style="color: #339933;">=</span> getResponseContentLength<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>contentLength <span style="color: #339933;">&gt;</span> <span style="color: #003399;">Integer</span>.<span style="color: #006633;">MAX_VALUE</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #666666; font-style: italic;">//guard below cast from overflow</span>
                    <span style="color: #000000; font-weight: bold;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">IOException</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Content too large to be buffered: &quot;</span><span style="color: #339933;">+</span> contentLength <span style="color: #339933;">+</span><span style="color: #0000ff;">&quot; bytes&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                <span style="color: #000066; font-weight: bold;">int</span> limit <span style="color: #339933;">=</span> getParams<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getIntParameter</span><span style="color: #009900;">&#40;</span>HttpMethodParams.<span style="color: #006633;">BUFFER_WARN_TRIGGER_LIMIT</span>, <span style="color: #cc66cc;">1024</span><span style="color: #339933;">*</span><span style="color: #cc66cc;">1024</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>contentLength <span style="color: #339933;">==</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #009900;">&#40;</span>contentLength <span style="color: #339933;">&gt;</span> limit<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                    LOG.<span style="color: #006633;">warn</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Going to buffer response body of large or unknown size. &quot;</span>
                            <span style="color: #339933;">+</span><span style="color: #0000ff;">&quot;Using getResponseBodyAsStream instead is recommended.&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                LOG.<span style="color: #006633;">debug</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Buffering response body&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #003399;">ByteArrayOutputStream</span> outstream <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">ByteArrayOutputStream</span><span style="color: #009900;">&#40;</span>
                        contentLength <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">?</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span><span style="color: #009900;">&#41;</span> contentLength <span style="color: #339933;">:</span> DEFAULT_INITIAL_BUFFER_SIZE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> buffer <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">4096</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                <span style="color: #000066; font-weight: bold;">int</span> len<span style="color: #339933;">;</span>
                <span style="color: #000000; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>len <span style="color: #339933;">=</span> instream.<span style="color: #006633;">read</span><span style="color: #009900;">&#40;</span>buffer<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                    outstream.<span style="color: #006633;">write</span><span style="color: #009900;">&#40;</span>buffer, <span style="color: #cc66cc;">0</span>, len<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                outstream.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                setResponseStream<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">responseBody</span> <span style="color: #339933;">=</span> outstream.<span style="color: #006633;">toByteArray</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">responseBody</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>    报WARN的条件是 ((contentLength == -1) || (contentLength > limit))，也就是说，或者是返回的HTTP头没有指定contentLength，或者是contentLength大于上限（默认是1M）。如果能确定返回结果的大小对程序没有显著影响，这个WARN就可以忽略，可以在日志的配置中把HttpClient的日志级别调到ERROR，不让它报出来。</p>
<p>    当然，这个警告也是有意义的，HttpClient建议使用InputStream getResponseBodyAsStream()代替byte[] getResponseBody()。对于返回结果很大或无法预知的情况，就需要使用InputStream getResponseBodyAsStream()，避免byte[] getResponseBody()可能带来的内存的耗尽问题。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/08/316.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>构建健壮的Java基准测试</title>
		<link>http://www.kafka0102.com/2010/08/312.html</link>
		<comments>http://www.kafka0102.com/2010/08/312.html#comments</comments>
		<pubDate>Sat, 14 Aug 2010 17:34:49 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[java benchmark]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=312</guid>
		<description><![CDATA[本周遇到几篇和基准测试相关的不错的文章，如果不是因为上周末鼓弄了一下各种锁的性能测试，我或许就会错过它们。两篇文章来自dw，分别是 Robust Java benchmarking, Part 1: Issues 和  Robust Java benchmarking, Part 2: Statistics and solutions，作者还有个专页 Java benchmarking article 提供一个Java基准测试的框架，感兴趣的可参考之。本文算是对Robust Java benchmarking, Part 1: Issues的一个简单的总结。在阅读Robust Java benchmarking两篇文章的过程中，我也看了些其中的参考文章，也有一些不错的可以拜读之。]]></description>
			<content:encoded><![CDATA[<p>本周遇到几篇和基准测试相关的不错的文章，如果不是因为上周末鼓弄了一下各种锁的性能测试，我或许就会错过它们。两篇文章来自dw，分别是<a href="http://www.ibm.com/developerworks/library/j-benchmark1.html" target="_blank"> Robust Java benchmarking, Part 1: Issues</a> 和 <a href="http://www.ibm.com/developerworks/java/library/j-benchmark2/index.html" target="_blank"> Robust Java benchmarking, Part 2: Statistics and solutions</a>，作者还有个专页<a href="http://www.ellipticgroup.com/html/benchmarkingArticle.html" target="_blank"> Java benchmarking article</a> 提供一个Java基准测试的框架，感兴趣的可参考之。本文算是对Robust Java benchmarking, Part 1: Issues的一个简单的总结。在阅读Robust Java benchmarking两篇文章的过程中，我也看了些其中的参考文章，也有一些不错的可以拜读之。</p>
<h2>1、度量执行时间</h2>
<p>基准测试通常的过程是：1）记录开始时间，2）执行代码，3）记录结束时间，4）计算时间差。Java中记录时间程序员们经常使用System.currentTimeMillis，不过该方法在精度上有偏差，这个偏差依操作系统的不同而不同，比如Win98可能会偏差55ms，Linux2.6可能偏差1ms。如果测试的task执行时间在毫秒级别，这个偏差就会影响结果的正确性了。JDK1.5中引入的System.nanoTime就是更好的选择，它在精度和准确性方面表现得都更好。而这种偏差以及其他因素可能引起的偏差，都在提醒我们，做基准测试时要使得task执行较长的时间。</p>
<h2>2、代码预热</h2>
<p>Java的执行过程是很复杂的，这其中会有很多因素影响到基准测试。通常来说，Java代码在开始执行阶段会相对很慢，之后会越来越快，直到达到稳定阶段，这一过程涉及的影响因素主要有：<br />
1）类加载。类加载涉及到文件读取、解析、校验等系列操作，所以在计算真正的task执行前需要先执行几遍task确保类加载都完成了。如果task涉及的条件分支很多，要确保各分支的代码都覆盖到。<br />
2）及时编译。JVM执行的是Java代码被翻译成的字节码，字节码的解释执行速度多数情况下是要比执行机器码慢的。所以，在Java代码执行过程中，JVM会根据执行情况将“热”的字节码编译成机器码加速执行，这就是JIT。Sun（Oracle？）的HotSpot JVM有两种启动模式，即client和server。启动时，client相比server做的优化更少，所以启动得更快。在运行时，同样一段代码，client需要1500次调用server需要10000次调用，使得JVM会将这段“热”代码编译成机器码。所以，如果要使得基准测试是在稳定阶段进行，就需要JVM将task中的代码动态编译成机器码。可以使用CompilationMXBean.getTotalCompilationTime函数以及-XX:+PrintCompilation启动参数查看及时编译情况。<br />
为解决上述两点提到的问题，一个可行的执行基准测试的过程如下：<br />
1. 执行task一次去加载所有的类。<br />
2. 执行task足够多次确保JVM的执行达到稳定阶段。<br />
3. 执行task一些次以得到task执行时间的评估值。<br />
4. 使用步骤3计算n，n是接下来task的执行次数，它要使得task的累积执行时间是足够的大。<br />
5. 度量执行n次task的总的执行时间。<br />
6. 评估单次（t/n）task的执行时间。</p>
<h2>3、动态优化</h2>
<p>动态编译不是一劳永逸的，它还涉及到一系列问题，突出的问题如下：<br />
1）Deoptimization：在Java程序运行过程中，同一段代码并不一定只被编译一次，JVM可能根据执行情况对已经编译过的代码段重新编译，以取得更好的优化效果。因为JVM通常编译的是一段“热”代码，但在运行时可能“热”代码周边的代码（比如一些并不经常走的分支）也“热”起来，这时整个代码段就可能需要重新编译。<br />
2）On-stack replacement：早期的HotSpot在编译“热”方法时，是在下次调用该方法时使用编译的字节码，本次的方法执行还是解释执行。所以，如果该次方法调用后再不调用这一方法，那么这个编译就没什么价值。比如一个极端的例子，在main函数里执行长循环操作，尽管HotSpot及时编译了机器码，但在循环执行过程中用不上，当循环结束，main也结束了，结果白白编译了机器码。所以，HotSpot后来引入了OSR，可以在方法执行过程中字节码替换成机器码。尽管OSR看起来很好，但OSR往往没有对编译的代码做最优化处理，这对基准测试来说就不是最好的选择。为避免OSR的问题，通常不要把所有的代码放到一个方法里。<br />
3）Dead-code elimination：Dead-code的情况很多，比如调用一个有返回值的方法，但返回值从来没有被调用者接收处理，JVM就可以对此做优化。这种优化在很多语言里都有，但对基准测试来说，这可不是好的情况。所以，写基准测试代码时要注意这个问题。</p>
<h2>4、Resource reclamation</h2>
<p>garbage collection and object finalization (GC/OF)是JVM自己的行为，如果程序员任其发展，它往往会在你不知道的时刻影响到基准测试。减少GC/OF的影响，通常有两种方法：1）是task运行时间长些，平衡掉GC的影响，2）是执行足够遍的task，并在每次执行后做System.gc和System.runFinalization处理，化被动为主动。</p>
<h2>5、Caching</h2>
<p>OS Cache和CPU Cache有时也会影响到基准测试。如果是测试文件IO操作，就不能忽略OS Cache的影响。如果是针对数值做测试，就可能要考虑CPU Cache的影响。</p>
<h2>6、其他因素</h2>
<p>除了上述几点，一些外界因素也需要考虑，比如测试执行过程中其他运行中的程序的影响，硬件的影响，JVM参数的影响等等。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/08/312.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java中各种锁类型的基准性能评测</title>
		<link>http://www.kafka0102.com/2010/08/298.html</link>
		<comments>http://www.kafka0102.com/2010/08/298.html#comments</comments>
		<pubDate>Tue, 10 Aug 2010 15:58:03 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[HashMap]]></category>
		<category><![CDATA[lock]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=298</guid>
		<description><![CDATA[周末对Java中各种类型的锁做了基准评测。测试的条件有两个：1）是10、50、100个不同的并发线程，2）是读写比例近似1:1,10:1,100:1,1000:1。测试方法是，对各种加锁的Map方法做性能评测，它们都是实现了MapWrapper接口的封装，测试的就是Map的get和put方法。测试的锁类型有：1）hashtable：直接测试Hashtable，2）synclock：对HashMap的方法直接加synchronized（理论上性能应和Hashtable相当），3）mutexlock：对HashMap的方法显示加Lock锁，4）rwlock：对HashMap加读写锁，5）concrrent：直接使用ConcurrentHashMap的方法，6）对HashMap读操作不加锁，写操作加Lock。]]></description>
			<content:encoded><![CDATA[<p>周末对Java中各种类型的锁做了基准评测。测试的条件有两个：1）是10、50、100个不同的并发线程，2）是读写比例近似1:1,10:1,100:1,1000:1。测试方法是，对各种加锁的Map方法做性能评测，它们都是实现了MapWrapper接口的封装，测试的就是Map的get和put方法。测试的锁类型有：1）hashtable：直接测试Hashtable，2）synclock：对HashMap的方法直接加synchronized（理论上性能应和Hashtable相当），3）mutexlock：对HashMap的方法显示加Lock锁，4）rwlock：对HashMap加读写锁，5）concrrent：直接使用ConcurrentHashMap的方法，6）对HashMap读操作不加锁，写操作加Lock。针对每种测试条件，起的每个线程执行特定次数（10万或100万）次读写操作，写入的内容是随机生成的整数，每种条件下一个线程要跑三遍，取总的处理时间的平均值作为计算结果。<br />
评测的代码如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> MapWrapper <span style="color: #009900;">&#123;</span>
&nbsp;
  <span style="color: #000066; font-weight: bold;">void</span> put<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> key,<span style="color: #003399;">Object</span> value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #003399;">Object</span> get<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000066; font-weight: bold;">void</span> clear<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #003399;">String</span> getName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> HashTableMapWrapper <span style="color: #000000; font-weight: bold;">implements</span> MapWrapper<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Map<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span> map<span style="color: #339933;">;</span>
&nbsp;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> HashTableMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Hashtable<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> clear<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map.<span style="color: #006633;">clear</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> get<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> put<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key, <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>key, value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #0000ff;">&quot;hashtable&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> SyncMapWrapper  <span style="color: #000000; font-weight: bold;">implements</span> MapWrapper<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Map<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span> map<span style="color: #339933;">;</span>
&nbsp;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> SyncMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashMap<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">synchronized</span> <span style="color: #000066; font-weight: bold;">void</span> clear<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map.<span style="color: #006633;">clear</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">synchronized</span> <span style="color: #003399;">Object</span>  get<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">synchronized</span> <span style="color: #000066; font-weight: bold;">void</span> put<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key, <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>key, value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #0000ff;">&quot;synclock&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> LockMapWrapper <span style="color: #000000; font-weight: bold;">implements</span> MapWrapper<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Map<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span> map<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Lock lock<span style="color: #339933;">;</span>
&nbsp;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> LockMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashMap<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    lock <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ReentrantLock<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> clear<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    lock.<span style="color: #006633;">lock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
      map.<span style="color: #006633;">clear</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">finally</span> <span style="color: #009900;">&#123;</span>
      lock.<span style="color: #006633;">unlock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> get<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    lock.<span style="color: #006633;">lock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">return</span> map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #666666; font-style: italic;">// TODO: handle exception</span>
    <span style="color: #009900;">&#125;</span><span style="color: #000000; font-weight: bold;">finally</span> <span style="color: #009900;">&#123;</span>
      lock.<span style="color: #006633;">unlock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> put<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key, <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    lock.<span style="color: #006633;">lock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
      map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>key, value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">finally</span> <span style="color: #009900;">&#123;</span>
      lock.<span style="color: #006633;">unlock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #0000ff;">&quot;mutexlock&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RWLockMapWrapper <span style="color: #000000; font-weight: bold;">implements</span> MapWrapper<span style="color: #009900;">&#123;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Map<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span> map<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Lock readLock<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Lock writeLock<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> RWLockMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashMap<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">final</span> ReentrantReadWriteLock lock <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ReentrantReadWriteLock<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    readLock <span style="color: #339933;">=</span> lock.<span style="color: #006633;">readLock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    writeLock <span style="color: #339933;">=</span> lock.<span style="color: #006633;">writeLock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> clear<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    writeLock.<span style="color: #006633;">lock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
      map.<span style="color: #006633;">clear</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">finally</span> <span style="color: #009900;">&#123;</span>
      writeLock.<span style="color: #006633;">unlock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> get<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    readLock.<span style="color: #006633;">lock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">return</span> map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #666666; font-style: italic;">// TODO: handle exception</span>
    <span style="color: #009900;">&#125;</span><span style="color: #000000; font-weight: bold;">finally</span> <span style="color: #009900;">&#123;</span>
      readLock.<span style="color: #006633;">unlock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> put<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key, <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    writeLock.<span style="color: #006633;">lock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
      map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>key, value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">finally</span> <span style="color: #009900;">&#123;</span>
      writeLock.<span style="color: #006633;">unlock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #0000ff;">&quot;rwlock&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ConcurrentMapWrapper  <span style="color: #000000; font-weight: bold;">implements</span> MapWrapper<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Map<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span> map<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> ConcurrentMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ConcurrentHashMap<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> clear<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map.<span style="color: #006633;">clear</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> get<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> put<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key, <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>key, value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #0000ff;">&quot;concrrent&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> WriteLockMapWrapper <span style="color: #000000; font-weight: bold;">implements</span> MapWrapper<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Map<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span> map<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> Lock lock<span style="color: #339933;">;</span>
&nbsp;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> WriteLockMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    map <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HashMap<span style="color: #339933;">&lt;</span>Object,Object<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    lock <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ReentrantLock<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> clear<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    lock.<span style="color: #006633;">lock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
      map.<span style="color: #006633;">clear</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">finally</span> <span style="color: #009900;">&#123;</span>
      lock.<span style="color: #006633;">unlock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> get<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> put<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key, <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    lock.<span style="color: #006633;">lock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
      map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>key, value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">finally</span> <span style="color: #009900;">&#123;</span>
      lock.<span style="color: #006633;">unlock</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  @Override
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> getName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #0000ff;">&quot;writelock&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> BenchMark <span style="color: #009900;">&#123;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">volatile</span> <span style="color: #000066; font-weight: bold;">long</span> totalTime<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> CountDownLatch latch<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> loop<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> threads<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">float</span> ratio<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> BenchMark<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> loop, <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> threads,<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">float</span> ratio<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">super</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">loop</span> <span style="color: #339933;">=</span> loop<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">threads</span> <span style="color: #339933;">=</span> threads<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">ratio</span> <span style="color: #339933;">=</span> ratio<span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">class</span> BenchMarkRunnable <span style="color: #000000; font-weight: bold;">implements</span> <span style="color: #003399;">Runnable</span><span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> MapWrapper mapWrapper<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> size<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> benchmarkRandomReadPut<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> MapWrapper mapWrapper,<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> loop<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Random</span> random <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Random</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000066; font-weight: bold;">int</span> writeTime <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
      <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> i<span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>i<span style="color: #339933;">&lt;</span>loop<span style="color: #339933;">;</span>i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> n <span style="color: #339933;">=</span> random.<span style="color: #006633;">nextInt</span><span style="color: #009900;">&#40;</span>size<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>mapWrapper.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>n<span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
          mapWrapper.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>n, n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
          writeTime<span style="color: #339933;">++;</span>
        <span style="color: #009900;">&#125;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> BenchMarkRunnable<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> MapWrapper mapWrapper,<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> size<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">mapWrapper</span> <span style="color: #339933;">=</span> mapWrapper<span style="color: #339933;">;</span>
      <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">size</span> <span style="color: #339933;">=</span> size<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> run<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">long</span> start <span style="color: #339933;">=</span> <span style="color: #003399;">System</span>.<span style="color: #006633;">currentTimeMillis</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      benchmarkRandomReadPut<span style="color: #009900;">&#40;</span>mapWrapper,loop<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">long</span> end <span style="color: #339933;">=</span> <span style="color: #003399;">System</span>.<span style="color: #006633;">currentTimeMillis</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      totalTime <span style="color: #339933;">+=</span> end<span style="color: #339933;">-</span>start<span style="color: #339933;">;</span>
      latch.<span style="color: #006633;">countDown</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> benchmark<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> MapWrapper mapWrapper<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">float</span> size <span style="color: #339933;">=</span> loop<span style="color: #339933;">*</span>threads<span style="color: #339933;">*</span>ratio<span style="color: #339933;">;</span>
    totalTime <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> k<span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>k<span style="color: #339933;">&lt;</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">;</span>k<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      latch <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CountDownLatch<span style="color: #009900;">&#40;</span>threads<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> i<span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>i<span style="color: #339933;">&lt;</span>threads<span style="color: #339933;">;</span>i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Thread</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> BenchMarkRunnable<span style="color: #009900;">&#40;</span>mapWrapper,<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span><span style="color: #009900;">&#41;</span>size<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">start</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
      <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
        latch.<span style="color: #006633;">await</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        e.<span style="color: #006633;">printStackTrace</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
      mapWrapper.<span style="color: #006633;">clear</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #003399;">Runtime</span>.<span style="color: #006633;">getRuntime</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">gc</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #003399;">Runtime</span>.<span style="color: #006633;">getRuntime</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">runFinalization</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003399;">Thread</span>.<span style="color: #006633;">sleep</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> rwratio <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1.0</span><span style="color: #339933;">/</span>ratio<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;[&quot;</span><span style="color: #339933;">+</span>mapWrapper.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #0000ff;">&quot;]threadnum[&quot;</span><span style="color: #339933;">+</span>threads<span style="color: #339933;">+</span><span style="color: #0000ff;">&quot;]ratio[&quot;</span><span style="color: #339933;">+</span>rwratio<span style="color: #339933;">+</span><span style="color: #0000ff;">&quot;]avgtime[&quot;</span><span style="color: #339933;">+</span>totalTime<span style="color: #339933;">/</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">+</span><span style="color: #0000ff;">&quot;]&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> benchmark2<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> loop, <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> threads,<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">float</span> ratio<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">final</span> BenchMark benchMark <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> BenchMark<span style="color: #009900;">&#40;</span>loop,threads,ratio<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">final</span> MapWrapper<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> wrappers <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> MapWrapper<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">new</span> HashTableMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,
        <span style="color: #000000; font-weight: bold;">new</span> SyncMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,
        <span style="color: #000000; font-weight: bold;">new</span> LockMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,
        <span style="color: #000000; font-weight: bold;">new</span> RWLockMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,
        <span style="color: #000000; font-weight: bold;">new</span> ConcurrentMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,
        <span style="color: #000000; font-weight: bold;">new</span> WriteLockMapWrapper<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> MapWrapper wrapper <span style="color: #339933;">:</span> wrappers<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      benchMark.<span style="color: #006633;">benchmark</span><span style="color: #009900;">&#40;</span>wrapper<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> test<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    benchmark2<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1000000</span>,<span style="color: #cc66cc;">10</span>,<span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//r:w 1:1</span>
    benchmark2<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1000000</span>,<span style="color: #cc66cc;">10</span>,0.1f<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//r:w 10:1</span>
    benchmark2<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1000000</span>,<span style="color: #cc66cc;">10</span>,0.01f<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//r:w 100:1</span>
    benchmark2<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1000000</span>,<span style="color: #cc66cc;">10</span>,0.001f<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//r:w 1000:1</span>
    <span style="color: #666666; font-style: italic;">/////</span>
    benchmark2<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1000000</span>,<span style="color: #cc66cc;">50</span>,0.1f<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//r:w 10:1</span>
    benchmark2<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1000000</span>,<span style="color: #cc66cc;">50</span>,0.01f<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//r:w 100:1</span>
    benchmark2<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1000000</span>,<span style="color: #cc66cc;">50</span>,0.001f<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//r:w 1000:1</span>
    <span style="color: #666666; font-style: italic;">/////</span>
    benchmark2<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">100000</span>,<span style="color: #cc66cc;">100</span>,1f<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//r:w 10:1</span>
    benchmark2<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">100000</span>,<span style="color: #cc66cc;">100</span>,0.1f<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//r:w 10:1</span>
    benchmark2<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">100000</span>,<span style="color: #cc66cc;">100</span>,0.01f<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//r:w 100:1</span>
    benchmark2<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">100000</span>,<span style="color: #cc66cc;">100</span>,0.001f<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//r:w 1000:1</span>
    <span style="color: #666666; font-style: italic;">////</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    test<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>测试是在本机进行的，JVM参数是： -Xms2048M -Xmx2048M -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:+HeapDumpOnOutOfMemoryError。依次是并发10、50、100个线程测试得到的数据表如下：<br />
<a href="http://www.kafka0102.com/wp-content/uploads/2010/08/lock_data.png"><img src="http://www.kafka0102.com/wp-content/uploads/2010/08/lock_data.png" alt="" title="lock_data" width="556" height="375" class="aligncenter size-full wp-image-305" /></a><br />
</br><br />
基于上面的数据使用openoffice做出的曲线对比图如下：<br />
1、并发10个线程的平均耗时曲线对比图：<br />
<a href="http://www.kafka0102.com/wp-content/uploads/2010/08/10_lock.jpg"><img src="http://www.kafka0102.com/wp-content/uploads/2010/08/10_lock.jpg" alt="" title="10_lock" width="599" height="330" class="aligncenter size-full wp-image-306" /></a><br />
<br />
2、并发50个线程的平均耗时曲线对比图：<br />
<a href="http://www.kafka0102.com/wp-content/uploads/2010/08/50_lock.jpg"><img src="http://www.kafka0102.com/wp-content/uploads/2010/08/50_lock.jpg" alt="" title="50_lock" width="604" height="439" class="aligncenter size-full wp-image-307" /></a><br />
<br />
3、并发100个线程的平均耗时曲线对比图：<br />
<a href="http://www.kafka0102.com/wp-content/uploads/2010/08/100_lock.jpg"><img src="http://www.kafka0102.com/wp-content/uploads/2010/08/100_lock.jpg" alt="" title="100_lock" width="598" height="362" class="aligncenter size-full wp-image-308" /></a><br />
<br />
对于测试数据来说，不必太当真，同样的用例跑几遍数据都会有偏差，但总体上数据间的对比应该基本一致的。对于上面的测试结果，其中并发50个线程时没有读写1:1的数据，这其实是我的一个失误，到整理结果时才发现。但在并发100个线程时，我调整了单线程的循环次数，从上面的100万次调整到10万次，这是因为在100万次时我的机器已经严重CPU耗尽，久久不出结果，并伴有大量全GC。</p>
<p>根据测试结果，可以得出下面的结论：<br />
1、读写比例相近（1:1）时，各种并发的速度差不多，只有ConcurrentHashMap因为分段加锁，性能稍好些。<br />
2、在几种并发及读写比例中，hashtable都表现得很差，即便是和显示加互斥锁的synclock和mutexlock相比。<br />
3、并发线程越多，锁的影响就越有体现。如果加锁的方法处理耗时更长，这种对比就更加明显（比如文件操作等）。<br />
4、直观的数据对比来说，在100线程并发读写1000:1的最大化条件下，表现最差的hashtable和表现最好的concurrent性能比是11:1,其他条件下的比例都在这之内。<br />
5、对比rwlock和writelock（rwlock加读写锁，writelock读不加锁写加互斥锁），读写锁的开销还是有一些的，因读写比例的不同而有几倍的差距。因为concurrent和writelock的区别在于concurrent是分段加锁，所以它俩的读写比例大时差别不大。<br />
6、综合分析，concurrent这种读不加锁、写加分段锁的做法是效果最好的（尽管读有时会脏读的情况）。</p>
<p>对于这种基准测试，如果你有更好更精确的方法，也请不吝分享之。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/08/298.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Solr源码分析]LRUCache和FastLRUCache实现分析</title>
		<link>http://www.kafka0102.com/2010/08/293.html</link>
		<comments>http://www.kafka0102.com/2010/08/293.html#comments</comments>
		<pubDate>Sun, 08 Aug 2010 16:01:42 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[cache]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[HashMap]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[源码分析]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=293</guid>
		<description><![CDATA[	在 [Solr 实践]Solr Cache使用介绍及分析 一文我有对Solr的LRUCache和FastLRUCache做了一些介绍，本文在此基础对其实现做些补充。
1、LRUCache的实现分析
	在分析LRUCache前先对LinkedHashMap做些介绍。LinkedHashMap继承于HashMap，它使用了一个双向链表来存储Map中的Entry顺序关系，这种顺序有两种，一种是LRU顺序，一种是插入顺序，这可以由其构造函数public LinkedHashMap(int initialCapacity,float loadFactor,                   boolean accessOrder)指定。所以，对于get、put、remove等操作，LinkedHashMap除了要做HashMap做的事情，还做些调整Entry顺序链表的工作。
	以get操作为例，如果是LRU顺序（accessOrder为true），Entry的recordAccess方法就调整get到的Entry到链表的头部去：

   public V get&#40;Object key&#41; &#123;
        Entry&#60;K,V&#62; e = &#40;Entry&#60;K,V&#62;&#41;getEntry&#40;key&#41;;
        if &#40;e [...]]]></description>
			<content:encoded><![CDATA[<p>	在 <a href="http://www.kafka0102.com/2010/08/267.html" target="blank">[Solr 实践]Solr Cache使用介绍及分析</a> 一文我有对Solr的LRUCache和FastLRUCache做了一些介绍，本文在此基础对其实现做些补充。</p>
<h2>1、LRUCache的实现分析</h2>
<p>	在分析LRUCache前先对LinkedHashMap做些介绍。LinkedHashMap继承于HashMap，它使用了一个双向链表来存储Map中的Entry顺序关系，这种顺序有两种，一种是LRU顺序，一种是插入顺序，这可以由其构造函数public LinkedHashMap(int initialCapacity,float loadFactor,                   boolean accessOrder)指定。所以，对于get、put、remove等操作，LinkedHashMap除了要做HashMap做的事情，还做些调整Entry顺序链表的工作。<br />
	以get操作为例，如果是LRU顺序（accessOrder为true），Entry的recordAccess方法就调整get到的Entry到链表的头部去：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">   <span style="color: #000000; font-weight: bold;">public</span> V get<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        Entry<span style="color: #339933;">&lt;</span>K,V<span style="color: #339933;">&gt;</span> e <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Entry<span style="color: #339933;">&lt;</span>K,V<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#41;</span>getEntry<span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>e <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
        e.<span style="color: #006633;">recordAccess</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">return</span> e.<span style="color: #006633;">value</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>    对于put来说，LinkedHashMap重写了addEntry方法：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">   <span style="color: #000066; font-weight: bold;">void</span> addEntry<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> hash, K key, V value, <span style="color: #000066; font-weight: bold;">int</span> bucketIndex<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        createEntry<span style="color: #009900;">&#40;</span>hash, key, value, bucketIndex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// Remove eldest entry if instructed, else grow capacity if appropriate</span>
        Entry<span style="color: #339933;">&lt;</span>K,V<span style="color: #339933;">&gt;</span> eldest <span style="color: #339933;">=</span> header.<span style="color: #006633;">after</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>removeEldestEntry<span style="color: #009900;">&#40;</span>eldest<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            removeEntryForKey<span style="color: #009900;">&#40;</span>eldest.<span style="color: #006633;">key</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>size <span style="color: #339933;">&gt;=</span> threshold<span style="color: #009900;">&#41;</span>
                resize<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">2</span> <span style="color: #339933;">*</span> table.<span style="color: #006633;">length</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>    addEntry中调用了boolean removeEldestEntry(Map.Entry<K,V> eldest)方法，默认实现一直返回false，也就是默认的Map是没有容量限制的。LinkedHashMap的子类可以复写该方法，当当前的size大于阈值时返回true，这样LinkedHashMap就可以从Entry顺序链表中删除最旧的Entry。这使得LinkedHashMap具有了Cache的功能，可以存储限量的元素，并具有两种可选的元素淘汰策略（LRU和FIFO），其中的LRU是最常用的。<br />
	Solr的LRUCache是基于LinkedHashMap实现的，所以LRUCache的实现真的很简单，这里列出其中核心的代码片断：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> init<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Map</span> args, <span style="color: #003399;">Object</span> persistence, <span style="color: #000000; font-weight: bold;">final</span> CacheRegenerator regenerator<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">//一堆解析参数参数初始化的代码</span>
	<span style="color: #666666; font-style: italic;">//map map    </span>
    map <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> LinkedHashMap<span style="color: #009900;">&#40;</span>initialSize, 0.75f, <span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      @Override
      <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">boolean</span> removeEldestEntry<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Map.<span style="color: #006633;">Entry</span></span> eldest<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>size<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> limit<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
          <span style="color: #666666; font-style: italic;">// increment evictions regardless of state.</span>
          <span style="color: #666666; font-style: italic;">// this doesn't need to be synchronized because it will</span>
          <span style="color: #666666; font-style: italic;">// only be called in the context of a higher level synchronized block.</span>
          evictions<span style="color: #339933;">++;</span>
          stats.<span style="color: #006633;">evictions</span>.<span style="color: #006633;">incrementAndGet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
          <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">true</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>persistence<span style="color: #339933;">==</span><span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #666666; font-style: italic;">// must be the first time a cache of this type is being created</span>
      persistence <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CumulativeStats<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    stats <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>CumulativeStats<span style="color: #009900;">&#41;</span>persistence<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">return</span> persistence<span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> put<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key, <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">synchronized</span> <span style="color: #009900;">&#40;</span>map<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>state <span style="color: #339933;">==</span> State.<span style="color: #006633;">LIVE</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        stats.<span style="color: #006633;">inserts</span>.<span style="color: #006633;">incrementAndGet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
      <span style="color: #666666; font-style: italic;">// increment local inserts regardless of state???</span>
      <span style="color: #666666; font-style: italic;">// it does make it more consistent with the current size...</span>
      inserts<span style="color: #339933;">++;</span>
      <span style="color: #000000; font-weight: bold;">return</span> map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>key,value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> get<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">synchronized</span> <span style="color: #009900;">&#40;</span>map<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Object</span> val <span style="color: #339933;">=</span> map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>state <span style="color: #339933;">==</span> State.<span style="color: #006633;">LIVE</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// only increment lookups and hits if we are live.</span>
        lookups<span style="color: #339933;">++;</span>
        stats.<span style="color: #006633;">lookups</span>.<span style="color: #006633;">incrementAndGet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>val<span style="color: #339933;">!=</span><span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
          hits<span style="color: #339933;">++;</span>
          stats.<span style="color: #006633;">hits</span>.<span style="color: #006633;">incrementAndGet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
      <span style="color: #009900;">&#125;</span>
      <span style="color: #000000; font-weight: bold;">return</span> val<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>  可以看到，LRUCache对读写操作直接加的互斥锁，多线程并发读写时会有锁的竞争问题。通常来说，Cache系统的读要远多于写，不能并发读是有些不够友好。不过，相比于Solr中其它耗时的操作来说，LRUCache的串行化读往往不会成为系统的瓶颈。LRUCache的优点是，直接套用LinkedHashMap，实现简单，缺点是，因为LinkedHashMap的get操作需要操作Entry顺序链表，所以必须对整个操作加锁。</p>
<h2>2、FastLRUCache的实现分析</h2>
<p>	Solr1.4引入FastLRUCache作为另一种可选的实现。FastLRUCache放弃了LinkedHashMap，而是使用现在很多Java Cache实现中使用的ConcurrentHashMap。但ConcurrentHashMap只提供了高性能的并发存取支持，并没有提供对淘汰数据的支持，所以FastLRUCache主要需要做的就是这件事情。FastLRUCache的存取操作都在ConcurrentLRUCache中实现，所以我们直接过渡到ConcurrentLRUCache的实现。<br />
	ConcurrentLRUCache的存取操作代码如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> V get<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> K key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">final</span> CacheEntry<span style="color: #339933;">&lt;</span>K,V<span style="color: #339933;">&gt;</span> e <span style="color: #339933;">=</span> map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>e <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>islive<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        stats.<span style="color: #006633;">missCounter</span>.<span style="color: #006633;">incrementAndGet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
      <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>islive<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      e.<span style="color: #006633;">lastAccessed</span> <span style="color: #339933;">=</span> stats.<span style="color: #006633;">accessCounter</span>.<span style="color: #006633;">incrementAndGet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">return</span> e.<span style="color: #006633;">value</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> V remove<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> K key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">final</span> CacheEntry<span style="color: #339933;">&lt;</span>K,V<span style="color: #339933;">&gt;</span> cacheEntry <span style="color: #339933;">=</span> map.<span style="color: #006633;">remove</span><span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>cacheEntry <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      stats.<span style="color: #006633;">size</span>.<span style="color: #006633;">decrementAndGet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000000; font-weight: bold;">return</span> cacheEntry.<span style="color: #006633;">value</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> put<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> K key, <span style="color: #000000; font-weight: bold;">final</span> V val<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>val <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">final</span> CacheEntry e <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CacheEntry<span style="color: #009900;">&#40;</span>key, val, stats.<span style="color: #006633;">accessCounter</span>.<span style="color: #006633;">incrementAndGet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">final</span> CacheEntry oldCacheEntry <span style="color: #339933;">=</span> map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>key, e<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000066; font-weight: bold;">int</span> currentSize<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>oldCacheEntry <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      currentSize <span style="color: #339933;">=</span> stats.<span style="color: #006633;">size</span>.<span style="color: #006633;">incrementAndGet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
      currentSize <span style="color: #339933;">=</span> stats.<span style="color: #006633;">size</span>.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>islive<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      stats.<span style="color: #006633;">putCounter</span>.<span style="color: #006633;">incrementAndGet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
      stats.<span style="color: #006633;">nonLivePutCounter</span>.<span style="color: #006633;">incrementAndGet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Check if we need to clear out old entries from the cache.</span>
    <span style="color: #666666; font-style: italic;">// isCleaning variable is checked instead of markAndSweepLock.isLocked()</span>
    <span style="color: #666666; font-style: italic;">// for performance because every put invokation will check until</span>
    <span style="color: #666666; font-style: italic;">// the size is back to an acceptable level.</span>
    <span style="color: #666666; font-style: italic;">// There is a race between the check and the call to markAndSweep, but</span>
    <span style="color: #666666; font-style: italic;">// it's unimportant because markAndSweep actually aquires the lock or returns if it can't.</span>
    <span style="color: #666666; font-style: italic;">// Thread safety note: isCleaning read is piggybacked (comes after) other volatile reads</span>
    <span style="color: #666666; font-style: italic;">// in this method.</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>currentSize <span style="color: #339933;">&gt;</span> upperWaterMark <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span>isCleaning<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>newThreadForCleanup<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Thread</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
          @Override
          <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> run<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            markAndSweep<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
          <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>.<span style="color: #006633;">start</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>cleanupThread <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        cleanupThread.<span style="color: #006633;">wakeThread</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
        markAndSweep<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">return</span> oldCacheEntry <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #339933;">?</span> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #339933;">:</span> oldCacheEntry.<span style="color: #006633;">value</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>	所有的操作都是直接调用map（ConcurrentHashMap）的。看下put中的代码，当map容量达到上限并且没有其他线程在清理数据（currentSize > upperWaterMark &#038;&#038; !isCleaning），就调用markAndSweep方法清理数据，可以有3种方式做清理工作：1）在该线程同步执行，2）即时启动新线程异步执行，3）提供单独的清理线程，即时唤醒它异步执行。</p>
<p>	markAndSweep方法那是相当的冗长，这里就不罗列出来。下面叙述下它的思路。</p>
<p>	对于ConcurrentLRUCache中的每一个元素CacheEntry，它有个属性lastAccessed，表示最后访问的数值大小。ConcurrentLRUCache中的stats.accessCounter是全局的自增整数，当put或get Entry时，Entry的lastAccessed会被更新成新自增得到的accessCounter。		ConcurrentLRUCache淘汰数据就是淘汰那些lastAccessed较小的Entry。因为ConcurrentLRUCache没有维护以lastAccessed排序的Entry链表（否则就是LRUCache了），所以淘汰数据时就需要遍历整个Map中的元素来淘汰合适的Entry。这是不是要扯上排序呢？其实不用那么大动干戈。</p>
<p>	这里定义几个变量，wantToKeep表示Map中需要保留的Entry个数，wantToRemove表示需要删除的个数（wantToRemove=map.size-wantToKeep),newestEntry是最大的lastAccessed值（初始是stats.accessCounter），这三个变量初始都是已知的，oldestEntry表示最小的lastAccessed，这个是未知的，可以在遍历Entry时通过比较递进到最小。Map中的Entry有3种:(a)是可以立刻判断出可以被淘汰的，也就是lastAccessed<(oldestEntry+wantToRemove)的，（b）是可以立刻判断出可以被保留的，也就是lastAccessed>(newestEntry-1000)的，（c）除上述两者之外的就是不能准确判断是否需要被淘汰的。对于遍历一趟Map中的Entry来说，极好的情况是如果淘汰掉满足（a）的Entry后Map大小降到了wantToKeep，这种情况的典型代表是对Cache只有get和put操作，使得lastAccessed在Map中能保持连续；极坏的情况是，可能满足（a）的Entry不够多甚至没有。但遍历一趟Map至少有一个效果是，会把需要处理的Entry范围缩小到满足（c）的。如此反复迭代，一定使得Map容量调到wantToKeep。而对这个淘汰，也要考虑一个现实情况是，wantToKeep往往是接近于map.size（比如等于0.9*map.size）的，如果remove操作不是很多，那么并不需要很多次遍历就可以完成清理工作。</p>
<p>	ConcurrentLRUCache淘汰数据的基本思想如上所述。它的执行过程可以分为3个阶段。第一个阶段就是遍历Map中的每个Entry，如果满足（a）就remove，满足（b）则跳过，满足（c）则放到新map中。一遍下来后，如果map.size还大于wantToKeep，第二个阶段就再重复上述过程（实现上，Solr用了个变量numPasses，似乎想做个开关控制遍历几次，当前就固定成一次）。完了如果map.size还大于wantToKeep，第三阶段再遍历一遍Map，但这次使用PriorityQueue来提取出还需要再淘汰的N个最old的Entry，这样一次下来就收工了。需要补充一点，上面提到的wantToKeep在代码中是acceptableWaterMark和lowerWaterMark，也就是如果遍历后达到acceptableWaterMark就算完成，但操作是按lowerWaterMark的要求来。</p>
<p>	这个算法的时间复杂度是2n+kln(k)（k值在实际大多数情况下会很小），相比于直接的堆排，通常会更快些。</p>
<h2>3、总结</h2>
<p>	LRUCache和FastLRUCache两种Cache实现是两种很不同的思路。两者的相同点是，都使用了现成的Map来维护数据。不同点是如何来淘汰数据。LRUCache（也就是LinkedHashMap）格外维护了一个结构，在做存取操作时同时更新该结构，优点在于淘汰操作是O(1)的，缺点是需要对存取操作加互斥锁。FastLRUCache正相反，它没有额外维护新的结构，可以由ConcurrentHashMap支持并发读，但put操作中如果需要淘汰数据，淘汰过程是O(n)的，因为整个过程不加锁，这也只会影响该次put的性能，而FastLRUCache也可选成起独立线程异步执行来降低影响。而另一个Cache实现Ehcache，它在淘汰数据就是同步的，不过它限定了每次淘汰数据的大小（通常都少于5个），所以同步情况下性能不会太受影响。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/08/293.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>分析多线程并发写HashMap线程被hang住的原因</title>
		<link>http://www.kafka0102.com/2010/08/286.html</link>
		<comments>http://www.kafka0102.com/2010/08/286.html#comments</comments>
		<pubDate>Fri, 06 Aug 2010 21:05:39 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[HashMap]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=286</guid>
		<description><![CDATA[在blogjava上看到一文  谁能帮忙解释一下为什么这个程序会死锁？，激发了我那能害死猫的好奇，所以很费劲的琢磨了这个问题。由于涉及的内容较多，就单独发文阐述一下。
文中提到的问题程序如下：

public class TestLock &#123;
  private final HashMap map = new HashMap&#40;&#41;;
  public TestLock&#40;&#41; &#123;
    final Thread t1 = new Thread&#40;&#41; &#123;
      @Override
      public void run&#40;&#41; &#123;
        for&#40;int i=0; i&#60;500000; i++&#41; &#123;
 [...]]]></description>
			<content:encoded><![CDATA[<p>在blogjava上看到一文 <a href="http://www.blogjava.net/zhvfeng/archive/2010/08/04/327956.html" target="blank"> 谁能帮忙解释一下为什么这个程序会死锁？</a>，激发了我那能害死猫的好奇，所以很费劲的琢磨了这个问题。由于涉及的内容较多，就单独发文阐述一下。</p>
<p>文中提到的问题程序如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TestLock <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">HashMap</span> map <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">HashMap</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">public</span> TestLock<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Thread</span> t1 <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Thread</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      @Override
      <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> run<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> i<span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span><span style="color: #cc66cc;">500000</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
          map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Integer</span><span style="color: #009900;">&#40;</span>i<span style="color: #009900;">&#41;</span>, i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;t1 over&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Thread</span> t2 <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Thread</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      @Override
      <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> run<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> i<span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span><span style="color: #cc66cc;">500000</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
          map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Integer</span><span style="color: #009900;">&#40;</span>i<span style="color: #009900;">&#41;</span>, i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;t2 over&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
    t1.<span style="color: #006633;">start</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    t2.<span style="color: #006633;">start</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">new</span> TestLock<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>	就是启了两个线程，不断的往一个非线程安全的HashMap中put内容，put的内容很简单，key和value都是从0自增的整数（这个put的内容做的并不好，以致于后来干扰了我分析问题的思路）。对HashMap做并发写操作，我原以为只不过会产生脏数据的情况，但反复运行这个程序，会出现线程t1、t2被hang住的情况，多数情况下是一个线程被hang住另一个成功结束，偶尔会两个线程都被hang住。说到这里，你如果觉得不好好学习ConcurrentHashMap而在这瞎折腾就手下留情跳过吧。<br />
	好吧，分析下HashMap的put函数源码看看问题出在哪，这里就罗列出相关代码（jdk1.6）：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> V put<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> K key, <span style="color: #000000; font-weight: bold;">final</span> V value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>key <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000000; font-weight: bold;">return</span> putForNullKey<span style="color: #009900;">&#40;</span>value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> hash <span style="color: #339933;">=</span> hash<span style="color: #009900;">&#40;</span>key.<span style="color: #006633;">hashCode</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> i <span style="color: #339933;">=</span> indexFor<span style="color: #009900;">&#40;</span>hash, table.<span style="color: #006633;">length</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span>Entry<span style="color: #339933;">&lt;</span>K,V<span style="color: #339933;">&gt;</span> e <span style="color: #339933;">=</span> table<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> e <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span> e <span style="color: #339933;">=</span> e.<span style="color: #006633;">next</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #666666; font-style: italic;">//@标记1</span>
      <span style="color: #003399;">Object</span> k<span style="color: #339933;">;</span>
      <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>e.<span style="color: #006633;">hash</span> <span style="color: #339933;">==</span> hash <span style="color: #339933;">&amp;&amp;</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>k <span style="color: #339933;">=</span> e.<span style="color: #006633;">key</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> key <span style="color: #339933;">||</span> key.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span>k<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">final</span> V oldValue <span style="color: #339933;">=</span> e.<span style="color: #006633;">value</span><span style="color: #339933;">;</span>
        e.<span style="color: #006633;">value</span> <span style="color: #339933;">=</span> value<span style="color: #339933;">;</span>
        e.<span style="color: #006633;">recordAccess</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">return</span> oldValue<span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    modCount<span style="color: #339933;">++;</span>
    addEntry<span style="color: #009900;">&#40;</span>hash, key, value, i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000066; font-weight: bold;">void</span> addEntry<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> hash, <span style="color: #000000; font-weight: bold;">final</span> K key, <span style="color: #000000; font-weight: bold;">final</span> V value, <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> bucketIndex<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">final</span> Entry<span style="color: #339933;">&lt;</span>K,V<span style="color: #339933;">&gt;</span> e <span style="color: #339933;">=</span> table<span style="color: #009900;">&#91;</span>bucketIndex<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    table<span style="color: #009900;">&#91;</span>bucketIndex<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Entry<span style="color: #339933;">&lt;</span>K,V<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span>hash, key, value, e<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>size<span style="color: #339933;">++</span> <span style="color: #339933;">&gt;=</span> threshold<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      resize<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">2</span> <span style="color: #339933;">*</span> table.<span style="color: #006633;">length</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000066; font-weight: bold;">void</span> resize<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> newCapacity<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">final</span> Entry<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> oldTable <span style="color: #339933;">=</span> table<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> oldCapacity <span style="color: #339933;">=</span> oldTable.<span style="color: #006633;">length</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>oldCapacity <span style="color: #339933;">==</span> MAXIMUM_CAPACITY<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      threshold <span style="color: #339933;">=</span> <span style="color: #003399;">Integer</span>.<span style="color: #006633;">MAX_VALUE</span><span style="color: #339933;">;</span>
      <span style="color: #000000; font-weight: bold;">return</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">final</span> Entry<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> newTable <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Entry<span style="color: #009900;">&#91;</span>newCapacity<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    transfer<span style="color: #009900;">&#40;</span>newTable<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    table <span style="color: #339933;">=</span> newTable<span style="color: #339933;">;</span>
    threshold <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span>newCapacity <span style="color: #339933;">*</span> loadFactor<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000066; font-weight: bold;">void</span> transfer<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> Entry<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> newTable<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">final</span> Entry<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> src <span style="color: #339933;">=</span> table<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> newCapacity <span style="color: #339933;">=</span> newTable.<span style="color: #006633;">length</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">long</span> time1 <span style="color: #339933;">=</span> <span style="color: #003399;">System</span>.<span style="color: #006633;">currentTimeMillis</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> j <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> j <span style="color: #339933;">&lt;</span> src.<span style="color: #006633;">length</span><span style="color: #339933;">;</span> j<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      Entry<span style="color: #339933;">&lt;</span>K,V<span style="color: #339933;">&gt;</span> e <span style="color: #339933;">=</span> src<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
      <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>e <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        src<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
        <span style="color: #000066; font-weight: bold;">int</span> k<span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//@标记2</span>
        <span style="color: #000000; font-weight: bold;">do</span> <span style="color: #009900;">&#123;</span>
          <span style="color: #000000; font-weight: bold;">final</span> Entry<span style="color: #339933;">&lt;</span>K,V<span style="color: #339933;">&gt;</span> next <span style="color: #339933;">=</span> e.<span style="color: #006633;">next</span><span style="color: #339933;">;</span>
          <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> i <span style="color: #339933;">=</span> indexFor<span style="color: #009900;">&#40;</span>e.<span style="color: #006633;">hash</span>, newCapacity<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
          e.<span style="color: #006633;">next</span> <span style="color: #339933;">=</span> newTable<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
          newTable<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> e<span style="color: #339933;">;</span>
          e <span style="color: #339933;">=</span> next<span style="color: #339933;">;</span>
          <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>k<span style="color: #339933;">++</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">1000</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #666666; font-style: italic;">//@标记3</span>
            <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">Thread</span>.<span style="color: #006633;">currentThread</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>
                <span style="color: #0000ff;">&quot;,e==next:&quot;</span><span style="color: #339933;">+</span><span style="color: #009900;">&#40;</span>e<span style="color: #339933;">==</span>e.<span style="color: #006633;">next</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #0000ff;">&quot;,e==next.next:&quot;</span><span style="color: #339933;">+</span><span style="color: #009900;">&#40;</span>e<span style="color: #339933;">==</span>e.<span style="color: #006633;">next</span>.<span style="color: #006633;">next</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>
                <span style="color: #0000ff;">&quot;,e:&quot;</span><span style="color: #339933;">+</span>e<span style="color: #339933;">+</span><span style="color: #0000ff;">&quot;,next:&quot;</span><span style="color: #339933;">+</span>e.<span style="color: #006633;">next</span><span style="color: #339933;">+</span><span style="color: #0000ff;">&quot;,eq:&quot;</span><span style="color: #339933;">+</span>e.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span>e.<span style="color: #006633;">next</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
              <span style="color: #003399;">Thread</span>.<span style="color: #006633;">sleep</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">2000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Exception</span> e2<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #009900;">&#125;</span>
&nbsp;
          <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span>e <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>  通过jconsole（或者thread dump），可以看到线程停在了transfer方法的while循环处。这个transfer方法的作用是，当Map中元素数超过阈值需要resize时，它负责把原Map中的元素映射到新Map中。我修改了HashMap，加上了@标记2和@标记3的代码片断，以打印出死循环时的状态，结果死循环线程总是出现类似这样的输出：“Thread-1,e==next:false,e==next.next:true,e:108928=108928,next:108928=108928,eq:true”。<br />
这个输出表明：<br />
  1）这个Entry链中的两个Entry之间的关系是：e=e.next.next，造成死循环。<br />
  2）e.equals(e.next)，但e!=e.next。因为测试例子中两个线程put的内容一样，并发时可能同一个key被保存了多个value，这种错误是在addEntry函数产生的，但这和线程死循环没有关系。</p>
<p>  接下来就分析transfer中那个while循环了。先所说这个循环正常的功能：src[j]保存的是映射成同一个hash值的多个Entry的链表，这个src[j]可能为null，可能只有一个Entry，也可能由多个Entry链接起来。假设是多个Entry，原来的链是(src[j]=a)->b（也就是src[j]=a,a.next=b,b.next=null），经过while处理后得到了(newTable[i]=b)->a。也就是说，把链表的next关系反向了。</p>
<p>  再看看这个while中可能在多线程情况下引起问题的语句。针对两个线程t1和t2,这里它们可能的产生问题的执行序列做些个人分析：</p>
<p>  1）假设同一个Entry列表[e->f->...]，t1先到，t2后到并都走到while中。t1执行“e.next = newTable[i];newTable[i] = e;”这使得e.next=null（初始的newTable[i]为null），newTable[i]指向了e。这时t2执行了“e.next = newTable[i];newTable[i] = e;”，这使得e.next=e，e死循环了。因为循环开始处的“final Entry<K,V> next = e.next;”，尽管e自己死循环了，在最后的“e = next;”后，两个线程都会跳过e继续执行下去。</p>
<p>  2）在while中逐个遍历Entry链表中的Entry而把next关系反向时，newTable[i]成为了被交换的引用，可疑的语句在于“e.next = newTable[i];”。假设链表e->f->g被t1处理成e<-f<-g，newTable[i]指向了g，这时t2进来了，它一执行“e.next = newTable[i];”就使得e->g，造成了死循环。所以，理论上来说，死循环的Entry个数可能很多。尽管产生了死循环，但是t1执行到了死循环的右边，所以是会继续执行下去的，而t2如果执行“final Entry<K,V> next = e.next;”的next为null，则也会继续执行下去，否则就进入了死循环。</p>
<p>  3）似乎情况会更复杂，因为即便线程跳出了死循环，它下一次做resize进入transfer时，有可能因为之前的死循环Entry链表而被hang住（似乎是一定会被hang住）。也有可能，在put检查Entry链表时（@标记1），因为Entry链表的死循环而被hang住。也似乎有可能，活着的线程和死循环的线程同时执行在while里后，两个线程都能活着出去。所以，可能两个线程平安退出，可能一个线程hang在transfer中，可能两个线程都被hang住而又不一定在一个地方。</p>
<p>  4）我反复的测试，出现一个线程被hang住的情况最多，都是e=e.next.next造成的，这主要就是例子put两份增量数据造成的。我如果去掉@标记3的输出，有时也能复现两个线程都被hang住的情况，但加上后就很难复现出来。我又把put的数据改了下，比如让两个线程put范围不同的数据，就能复现出e=e.next，两个线程都被hang住的情况。</p>
<p>  上面罗哩罗嗦了很多，一开始我简单的分析后觉得似乎明白了怎么回事，可现在仔细琢磨后似乎又不明白了许多。有一个细节是，每次死循环的key的大小也是有据可循的，我就不打哈了。感觉，如果样本多些，可能出现问题的原因点会很多，也会更复杂，我姑且不再蛋疼下去。至于有人提到ConcurrentHashMap也有这个问题，我觉得不大可能，因为它的put操作是加锁的，如果有这个问题就不叫线程安全的Map了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/08/286.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>使用JRebel提供对Java web开发的热部署</title>
		<link>http://www.kafka0102.com/2010/07/258.html</link>
		<comments>http://www.kafka0102.com/2010/07/258.html#comments</comments>
		<pubDate>Thu, 29 Jul 2010 13:32:08 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[jrebel]]></category>
		<category><![CDATA[热部署]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=258</guid>
		<description><![CDATA[	这几天在写Java Web页面，开发环境是linux+eclipse+maven+jetty。开发java web最烦的就是改个文件需要重启web server，尽管现在的web server（比如小野猫）支持了热部署，不过其实现相当于重启了web server，如果文件多些初始化复杂些，重启的时间也够受的。对于开发的IDE来说，myeclipse是个不错的选择，它能对修改的文件自动部署到web server（eclipse wtp就没做这个支持，但我们也可以投机的对部署目录和开发目录做个软链），不多我试用了其最新的8.5版本，在本本上响应速度有些迟缓，影响编码情绪。而且，因为环境需要，最后开发环境定位eclipse+maven+jetty（maven提供了jetty的plugin用于开发测试），并且找到了JRebel这个强悍的能提供对Web server的热部署到工具，它不像web server那样需要重启服务，而是动态的加载修改的文件，所以反应速度上要好很多，它除了可以热加载class、jsp文件，也可以是spring、hibernate等配置文件。]]></description>
			<content:encoded><![CDATA[<p>这几天在写Java Web页面，开发环境是linux+eclipse+maven+jetty。开发java web最烦的就是改个文件需要重启web server，尽管现在的web server（比如小野猫）支持了热部署，不过其实现相当于重启了web server，如果文件多些初始化复杂些，重启的时间也够受的。对于开发的IDE来说，myeclipse是个不错的选择，它能对修改的文件自动部署到web server（eclipse wtp就没做这个支持，但我们也可以投机的对部署目录和开发目录做个软链），不过我试用了其最新的8.5版本，在本本上响应速度有些迟缓，影响编码情绪。而且，因为环境需要，最后开发环境定位eclipse+maven+jetty（maven提供了jetty的plugin用于开发测试），并且找到了JRebel这个强悍的能提供对Web server的热部署的工具，它不像web server那样需要重启服务，而是动态的加载修改的文件，所以反应速度上要好很多，它除了可以热加载class、jsp文件，也可以是spring、hibernate等配置文件。</p>
<p>可以从 <a href="http://www.zeroturnaround.com/jrebel/" target="blank">jrebel</a> 得到JRebel，它不是个免费软件，但有30天的试用期，所以我先混个月再说。如果你使用eclipse wtp，可以参考<a href="http://www.zeroturnaround.com/jrebel/eclipse-jrebel-tutorial/" target="blank">eclipse-jrebel-tutorial</a>来安装使用之。下面列出linux+eclipse+maven+jetty环境中的安装步骤（我没有在其网站上找到完整的安装步骤）：</p>
<p>1、从<a href="http://www.zeroturnaround.com/jrebel/current/" target="blank">http://www.zeroturnaround.com/jrebel/current/</a>下载最新的JRebel安装包，根据readme.txt中的说明安装JRebel，我的安装路径是：/home/kafka/tools/jrebel。</p>
<p>2、修改项目的pom.xml文件，将已有的jetty plugin配置修改成：</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.mortbay.jetty<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>maven-jetty-plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
					<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;scanIntervalSeconds<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>0<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/scanIntervalSeconds<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>在&lt;build&gt;&lt;plugins&gt;中加入：</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">	 <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.zeroturnaround<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>javarebel-maven-plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
			 <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>generate-rebel-xml<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>process-resources<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/phase<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		         	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>generate<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goal<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
			<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/execution<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
		<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/executions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
	<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>然后运行mvn javarebel:generate。可以在target/classes路径中看到新生成的rebel.xml。也可以参考http://www.zeroturnaround.com/jrebel/configuration/maven/做更多了解。</p>
<p>3、修改环境变量MAVEN_OPTS。我这是个人单机，所以直接在.bashrc中配置：export MAVEN_OPTS=&#8221;-noverify -javaagent:/home/kafka/tools/JRebel/jrebel.jar&#8221;，javaagent指定的就是刚才jrebel.jar安装的路径。</p>
<p>4、好了，可以收工了。运行mvn jetty:run，在启动信息中可以看到jrebel相关的信息。后续对文件的修改也可以在console上看到jrebel reloading相应文件的信息。</p>
<p>浏览JRebel网站，发现几篇很好的文章 http://www.zeroturnaround.com/blog/reloading-objects-classes-classloaders/ ，是关于JRebel的实现原理、Classloader及Web server热部署的实现原理方面的。最近也在看terracotta dso，其和JRebel都用到了java instrument，有时间好好琢磨琢磨。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/07/258.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>对mongodb进行java编程</title>
		<link>http://www.kafka0102.com/2010/07/209.html</link>
		<comments>http://www.kafka0102.com/2010/07/209.html#comments</comments>
		<pubDate>Sat, 03 Jul 2010 17:16:59 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[mongodb]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=209</guid>
		<description><![CDATA[	本周实验性地使用上mongodb，应用场景很简单，所以现在对mongodb了解也不是很深入。本文主要介绍mongodb的java客户端编程，这方面的内容也很简单，这里只是做个总结。不得不说，像mongodb这种介于kv和sql之间的存储，对很多的互联网应用很合适。mongodb现在的应用案例已经很多，并且社区的活跃度很高（国内也有不少人对其有很深的研究，如果有时间和精力，或许我也会投入一些对mongodb的研究），很值得期待。]]></description>
			<content:encoded><![CDATA[<p>	本周实验性地使用上mongodb，应用场景很简单，所以现在对mongodb了解也不是很深入。本文主要介绍mongodb的java客户端编程，这方面的内容也很简单，这里只是做个总结。不得不说，像mongodb这种介于kv和sql之间的存储，对很多的互联网应用很合适。mongodb现在的应用案例已经很多，并且社区的活跃度很高（国内也有不少人对其有很深的研究，如果有时间和精力，或许我也会投入一些对mongodb的研究），很值得期待。</p>
<p>	言归正传，下面总结下使用Java开发mongodb应用的一些点滴。在Java中和mongodb交互的最直接的选择就是使用MongoDB Java Driver，其下载地址是：http://github.com/mongodb/mongo-java-driver/downloads。总的来说，在Java中操作mongodb的API还是很简洁，下面对其一些常见的使用做些介绍。</p>
<h2>1、连接数据库</h2>
<p>	和mongodb建立连接的示例代码如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	Mongo m <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Mongo<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span>,<span style="color: #cc66cc;">27017</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	DB db <span style="color: #339933;">=</span> m.<span style="color: #006633;">getDB</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;db_test&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>	尽管这里获得了表示mongodb的db_test数据库连接的对象db，但这时并没有真正和mongodb建立连接，所以即便这时数据库没起来也不会抛出异常，尽管你还是需要catch它的实例化过程。mongodb的java driver对连接做了池化处理，所以应用中只需要实例化一个Mongo对象即可，对它的操作是线程安全的，这对开发使用来说真的是很方便。</p>
<h2>2、取得DBCollection</h2>
<p>	mongodb中的collection在Java中使用DBCollection表示（这是一个抽象类，尽管你不必需要知道），创建DBCollection实例也是一行代码，和创建DB实例一样，这个操作并不涉及真正的和数据库之间的通信。</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	DBCollection coll <span style="color: #339933;">=</span> db.<span style="color: #006633;">getCollection</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;collection1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>	要获得类似mysql中“show tables”功能，可以使用如下代码：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	Set<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;</span> colls <span style="color: #339933;">=</span> db.<span style="color: #006633;">getCollectionNames</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> s <span style="color: #339933;">:</span> colls<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	    <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>s<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<h2>3、插入文档</h2>
<p>	mongodb存储JSON格式的文档，而在Java中表示这种数据格式的最简便的类就是Map了。MongoDB Java Driver中提供的BasicDBObject就是个Map（它继承自LinkedHashMap并实现DBObject接口），它会将Map中的数据转换成BSON格式传输到mongodb。下面是插入文档的示例：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	DBCollection coll <span style="color: #339933;">=</span> db.<span style="color: #006633;">getCollection</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;collection1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	BasicDBObject doc <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> BasicDBObject<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	doc.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;name&quot;</span>, <span style="color: #0000ff;">&quot;kafka0102&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	doc.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;age&quot;</span>, <span style="color: #cc66cc;">28</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	doc.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;time&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Date</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	coll.<span style="color: #006633;">insert</span><span style="color: #009900;">&#40;</span>doc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>	mongodb中每个插入的文档会产生个唯一标识_id。当调用coll.insert(doc);时，driver会检查其中是否有_id字段，如果没有则自动生成ObjectId实例来作为_id的值，这个ObjectId由4部分编码而成：当前时间、机器标识、进程号和自增的整数。<br />
	insert函数也支持插入文档列表：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">insert<span style="color: #009900;">&#40;</span>List<span style="color: #339933;">&lt;</span>DBObject<span style="color: #339933;">&gt;</span> list<span style="color: #009900;">&#41;</span></pre></div></div>

<p>而提交操作也有update( DBObject q , DBObject o )、remove( DBObject o )。</p>
<h2>4、查询文档</h2>
<h3>4.1、findOne</h3>
<p>	findOne是查询满足条件的第一条记录（不意味着数据库满足条件的只有一条记录），查询条件使用DBObject表示，示例如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	DBCollection coll <span style="color: #339933;">=</span> db.<span style="color: #006633;">getCollection</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;collection1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	BasicDBObject cond <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> BasicDBObject<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	cond.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;name&quot;</span>, <span style="color: #0000ff;">&quot;kafka0102&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	cond.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;age&quot;</span>, <span style="color: #cc66cc;">28</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	DBObject ret <span style="color: #339933;">=</span> coll.<span style="color: #006633;">findOne</span><span style="color: #009900;">&#40;</span>cond<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>ret<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>	返回结果是个DBObject，可以通过get(key)来取值。对于查询条件，可以通过嵌套多层来表示复杂的格式，比如：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	query <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> BasicDBObject<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        query.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;i&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> BasicDBObject<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$gt&quot;</span>, <span style="color: #cc66cc;">50</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  <span style="color: #666666; font-style: italic;">// e.g. find all where i &gt; 50</span></pre></div></div>

<h3>4.2、find</h3>
<p>	find函数是查询集合的，它返回的DBCursor是DBObject的迭代器，使用示例如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	DBCollection coll <span style="color: #339933;">=</span> db.<span style="color: #006633;">getCollection</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;collection1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	BasicDBObject cond <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> BasicDBObject<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	cond.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;i&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> BasicDBObject<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$gt&quot;</span>, <span style="color: #cc66cc;">20</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$lte&quot;</span>, <span style="color: #cc66cc;">30</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	DBCursor ret <span style="color: #339933;">=</span> coll.<span style="color: #006633;">find</span><span style="color: #009900;">&#40;</span>cond<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000000; font-weight: bold;">while</span><span style="color: #009900;">&#40;</span>ret.<span style="color: #006633;">hasNext</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	   <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>ret.<span style="color: #006633;">next</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<h2>5、使用索引</h2>
<p>	创建索引语句如：coll.createIndex(new BasicDBObject(&#8220;i&#8221;, 1)); ，其中i表示要索引的字段，1表示升序（-1表示降序）。可以看到，DBObject成为java客户端通用的结构表示。查看索引使用DBCollection.getIndexInfo()函数。</p>
<h2>6、MongoDB Java Driver的并发性</h2>
<p>	前面提到，Java MongoDB Driver使用了连接的池化处理，这个连接池默认是保持10个连接，可以通过Option进行修改，在应用中使用Mongo的一个实例即可。连接池中的每个连接使用DBPort结构表示（而不是DBCollection），并寄存于DBPortPool中，所以对DBCollection的操作并不意味着使用同一个连接。如果在应用的一次请求过程中，需要保证使用同一个连接，可以使用下面的代码片断：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	DB db...<span style="color: #339933;">;</span>
	db.<span style="color: #006633;">requestStart</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">//code....</span>
	db.<span style="color: #006633;">requestDone</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>	在requestStart和requestDone之间使用的连接就不是来自于DBPortPool，而是当前线程中的ThreadLocal<MyPort>结构变量（MyPort中保持了DBPort成员）。</p>
<h2>7、其他选择</h2>
<p>	尽管Java mongodb driver很不错，但就像很多人不使用JDBC而使用一些ORM框架，mongodb的java客户端也有其他的选择。<br />
	1）对POJO和DAO的支持。对于那些热衷ORM的人来说，Morphia（http://code.google.com/p/morphia/wiki/QuickStart）是个不错的选择，它通过在POJO中添加注释来实现映射，并提供对DAO的CRUD操作的支持。<br />
	2）对DSL的支持。Sculptor就是这样的东西，使用者编写中立的DSL文件，Sculptor将其翻译成代码。这通常不具有吸引力，除非是多语言的应用，能将DSL翻译成多种编程语言，否则除了增加学习成本，没什么收益。<br />
	3）对JDBC的支持。mongo-jdbc是这样的东西，但现在还是实验性质的。它或许是想亲近Java程序员，不过它显然不能完全兼容JDBC，而很多Java程序员对JDBC也并不感冒，所以它不是很值得使用。</p>
<h2>8、参考资料</h2>
<p>1、http://www.mongodb.org/display/DOCS/Java+Tutorial<br />
2、http://api.mongodb.org/java/2.0/index.html</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/07/209.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>使用依赖注入框架Google Guice替代new和工厂类</title>
		<link>http://www.kafka0102.com/2010/06/193.html</link>
		<comments>http://www.kafka0102.com/2010/06/193.html#comments</comments>
		<pubDate>Fri, 25 Jun 2010 20:07:22 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[framework]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[di]]></category>
		<category><![CDATA[guice]]></category>
		<category><![CDATA[ioc]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=193</guid>
		<description><![CDATA[	在新系统中使用了Guice来统一了对象注入和创建方式，也不是刻意为之，而是由两个经典问题引起的：
	1）对于对象的创建，可以使用new、静态工厂、抽象工厂等方式，使得对象创建方式不统一，而使用哪种方式最好也很难有定论，并且随着代码的变化，创建方式也可能会需要有更好的变化。
	2）对于类成员的设置，最直接的是在类内部直接创建，但这样硬编码会影响灵活的测试性，解决的方法是通过外部注入成员，好处自不必说，但在一个复杂的系统中，类之间的关联及层次关系，使得一个上层对象的创建往往需要依赖多个下层的类，使得对象创建代码变的冗余而复杂。
	解决上面两个问题，我就想到了依赖注入（DI）框架（也被成为IOC容器，取控制反转之意），我需要选择一个得手的依赖注入框架来满足需求。]]></description>
			<content:encoded><![CDATA[<h2>1、使用依赖注入</h2>
<p>	在新系统中使用了Guice来统一了对象注入和创建方式，也不是刻意为之，而是由两个经典问题引起的：<br />
	1）对于对象的创建，可以使用new、静态工厂、抽象工厂等方式，使得对象创建方式不统一，而使用哪种方式最好也很难有定论，并且随着代码的变化，创建方式也可能会需要有更好的变化。<br />
	2）对于类成员的设置，最直接的是在类内部直接创建，但这样硬编码会影响灵活的测试性，解决的方法是通过外部注入成员，好处自不必说，但在一个复杂的系统中，类之间的关联及层次关系，使得一个上层对象的创建往往需要依赖多个下层的类，使得对象创建代码变的冗余而复杂。<br />
	解决上面两个问题，我就想到了依赖注入（DI）框架（也被成为IOC容器，取控制反转之意），我需要选择一个得手的依赖注入框架来满足需求。</p>
<h2>2、选择google guice</h2>
<p>	说到依赖注入框架，最大牌的就是Spring了。我很久之前也搞过一点Spring，使用上也很简单，但我最终选择了google的Guice。如果非要说个理由，一是Guice使用也很简单，二是Spring有点大并且它原生是需要个配置文件而我不想要配置文件（Spring2引入注释后，配置方面也可以很简化，应该也可以抛弃配置文件直接代码绑定，但这种非主流做法我也不曾验证过其有多麻烦），三是我想搞搞没搞过的。<br />
	Guice是google的”疯狂的Bob“开发的，开源后也有不错的活跃度。Bob当初没有选择Spring而是另造轮子，原因也主要是Spring配置的繁琐（代码和配置的分离会对测试维护等造成麻烦）、Spring相对的低性能（对大多数应用来说，Spring的性能是可以接受的说，尽管Guice性能确实比Spring好很多）。但轮子既然造出来并发布出来，自然会有人将其和Spring做对比。这方面我不想牵涉更多精力，其实两个选择都不错，了解它们各自的特点，就自己的应用需求，选择更合适的即可。就大多数应用系统（尤其是SSH配套系统），Spring还是不错的选择。再有，从发展前景来说，火爆成熟并有专业公司推动的Spring无疑会比形单影只的Guice会更有发展。如果真就同类DI框架间比较，倒可以将Guice和老牌的PicoContainer做些比较（PicoContainer和Spring在同一时期诞生，到现在也是不温不火，但还在持续更新中）。</p>
<h2>3、使用google guice</h2>
<h3>3.1、基本使用</h3>
<p>    好吧，你不要嫌我罗嗦，我只能假定你对Guice是个新手并真的对它有些兴趣，所以亲手写出示例代码来说明Guice的使用及其特点。先上代码，看下很简单的示例代码：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> Foo <span style="color: #009900;">&#123;</span>
   <span style="color: #000066; font-weight: bold;">void</span> foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> Bar <span style="color: #009900;">&#123;</span>
   <span style="color: #000066; font-weight: bold;">void</span> bar<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> FooImpl1 <span style="color: #000000; font-weight: bold;">implements</span> Foo <span style="color: #009900;">&#123;</span>
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;FooImpl1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> BarImpl1 <span style="color: #000000; font-weight: bold;">implements</span> Bar <span style="color: #009900;">&#123;</span>
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> bar<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;BarImpl1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> BeanService1 <span style="color: #009900;">&#123;</span>
   <span style="color: #000000; font-weight: bold;">private</span> Foo foo<span style="color: #339933;">;</span>
   <span style="color: #000000; font-weight: bold;">private</span> Bar bar<span style="color: #339933;">;</span>
   @Inject
   <span style="color: #000000; font-weight: bold;">public</span> BeanService1<span style="color: #009900;">&#40;</span>Foo foo, Bar bar<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">foo</span> <span style="color: #339933;">=</span> foo<span style="color: #339933;">;</span>
       <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">bar</span> <span style="color: #339933;">=</span> bar<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   @Override
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">String</span> toString<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #0000ff;">&quot;BeanService1 [bar=&quot;</span> <span style="color: #339933;">+</span> bar <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;, foo=&quot;</span> <span style="color: #339933;">+</span> foo <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;]&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> BeanService1Module <span style="color: #000000; font-weight: bold;">implements</span> Module <span style="color: #009900;">&#123;</span>
       <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> configure<span style="color: #009900;">&#40;</span>Binder binder<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
           binder.<span style="color: #006633;">bind</span><span style="color: #009900;">&#40;</span>Foo.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">to</span><span style="color: #009900;">&#40;</span>FooImpl1.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
           binder.<span style="color: #006633;">bind</span><span style="color: #009900;">&#40;</span>Bar.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">to</span><span style="color: #009900;">&#40;</span>BarImpl1.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
       <span style="color: #009900;">&#125;</span>
   <span style="color: #009900;">&#125;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">       Injector injector <span style="color: #339933;">=</span> Guice.<span style="color: #006633;">createInjector</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> BeanService1Module<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
       BeanService1 bs <span style="color: #339933;">=</span> injector.<span style="color: #006633;">getInstance</span><span style="color: #009900;">&#40;</span>BeanService1.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
       <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>bs<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>    上面的示例没什么逻辑可言，BeanService1有两个成员变量，通过构造函数注入。这里使用Guice来创建BeanService1对象的工作有3个：<br />
    1）使用注释@Inject来标识BeanService1中需要被注入的成员，这里使用构造函数方式注入。<br />
    2）创建实现了Module接口的BeanService1Module，Module接口只有一个void configure(Binder binder)，在这个函数中可以做绑定操作，比如将Foo接口和FooImpl1绑定起来，这使得Guice在运行时动态创建BeanService1对象时，当调用其被标识为@Inject的构造函数时，会查找参数列表成员是否有绑定的类型。<br />
    3）使用Guice.createInjector(Module&#8230; module)函数来创建Injector，Injector就相当于Factory，后续就可以调用其getInstance创建对象。<br />
    很简单吧，使用Guice不会比自己写工厂方法麻烦多少，下面再具体介绍其注入和绑定的其他方式。</p>
<h3>3.2、注入和绑定的方式</h3>
<p>    除了上面提到的使用@Inject注入构造函数的方式，Guice还支持另两种常用的方式：<br />
    2）@Inject到类的成员变量，上面的例子就可修改成：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> BeanService1 <span style="color: #009900;">&#123;</span>
   @Inject <span style="color: #000000; font-weight: bold;">private</span> Foo foo<span style="color: #339933;">;</span>
   @Inject <span style="color: #000000; font-weight: bold;">private</span> Bar bar<span style="color: #339933;">;</span>
&nbsp;
   <span style="color: #000000; font-weight: bold;">public</span> BeanService1<span style="color: #009900;">&#40;</span>Foo foo, Bar bar<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">foo</span> <span style="color: #339933;">=</span> foo<span style="color: #339933;">;</span>
       <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">bar</span> <span style="color: #339933;">=</span> bar<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
&nbsp;
   <span style="color: #000000; font-weight: bold;">public</span> BeanService1<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>    当然，这次需要个默认构造函数的。<br />
    3）@Inject到类的方法，上面的例子就可修改成：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> BeanService1 <span style="color: #009900;">&#123;</span>
   <span style="color: #000000; font-weight: bold;">private</span> Foo foo<span style="color: #339933;">;</span>
   <span style="color: #000000; font-weight: bold;">private</span> Bar bar<span style="color: #339933;">;</span>
&nbsp;
   <span style="color: #000000; font-weight: bold;">public</span> BeanService1<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #009900;">&#125;</span>
   @Inject
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setFoo<span style="color: #009900;">&#40;</span>Foo foo<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">foo</span> <span style="color: #339933;">=</span> foo<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   @Inject
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setBar<span style="color: #009900;">&#40;</span>Bar bar<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">bar</span> <span style="color: #339933;">=</span> bar<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>    注释完了，就需要一种绑定关系，以使Guice能确定该如何注入。上面示例中的绑定方式是最常见的，就是将一个接口绑定到一个实现类上。Guice还支持的绑定如下：<br />
    2）绑定自身。像BeanService1是个实现类而没有实现什么接口，它当然也可能被其他类注入，可以使用 binder.bind(BeanService1.class);绑定自身，尽管这样做没什么意义，对于注入的类参数，Guice识别出来后会直接创建。<br />
    3）绑定注释和实例。如果被注入的是如String、int这样的基本类型，需要做两件事情：一是对被注入的参数加上名称注释@Named，如下所示：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">  @Inject
   <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> setName<span style="color: #009900;">&#40;</span>@Named<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;beanService1Name&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #003399;">String</span> name<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">name</span> <span style="color: #339933;">=</span> name<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span></pre></div></div>

<p>二是调用 bind(String.class).annotatedWith(Names.named(&#8220;beanService1Name&#8221;)).toInstance(“kafka0102”); 来将实例值和注释绑定上。对于@Named，它可作用于任何类型的变量，所以，如果某个被注入的参数需要指定为特定的对象，可以使用该方式。而对于基本类型，最好都指定@Named，以避免之间的冲突。<br />
    4）绑定Provider。有些时候对象的创建是不适合使用@Injectt注入的，比如被创建的对象的构造依赖于复杂的外部环境，再比如需要被构造的对象来自于第三方库。此时可以有两种解决方法，一是在AbstractModule的子类中提供@Provides方法，示例如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> BeanService1Module <span style="color: #000000; font-weight: bold;">implements</span> Module <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> configure<span style="color: #009900;">&#40;</span>Binder binder<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			binder.<span style="color: #006633;">bind</span><span style="color: #009900;">&#40;</span>Bar.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">to</span><span style="color: #009900;">&#40;</span>BarImpl1.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		@Provides
		<span style="color: #000000; font-weight: bold;">public</span> Foo provideFoo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">//create...</span>
			<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<p>	另一种方法是提供实现了接口</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> Provider<span style="color: #339933;">&lt;</span>T<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
  		T get<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<p>	的实现类，并通过诸如binder.bind(Foo.class).toProvider(FooProvider.class);来绑定。<br />
	对于构造函数注入、成员变量注入、成员方法注入这三种经典的注入方式，选择上来说，构造函数注入最直接明了，推荐使用，有时构造函数中需要做些初始化操作，这时其他两种注入方式就不能胜任；对于成员变量注入，这有点反模式的味道，尤其是对于私有成员来说，不建议使用；使用成员方法注入也是很好的方式，在一些情况下（比如被注入的方法在父类中存在），使用方法注入会更合适。</p>
<h3>3.3、其他</h3>
<p>	1、如果被注入的是范型类型的类（比如List<String>），Guice提供了TypeLiteral来创建绑定，比如示例代码binder.bind(new TypeLiteral<List<String>>() {}).toInstance(new ArrayList<String>());<br />
	2、Guice对被被注入的参数要求不能为null，如果有可接受null的需求，可以对参数提供注释@Nullable解决。<br />
	3、对创建的实例，Guice默认都是new一个新的，可以对类指定如@Singleton、@SessionScoped、@RequestScoped这样的Scope来表示创建什么范围的实例（也可以通过binder.bind(Bar.class).to(BarImpl1.class).in(Singleton.class);这样来解决）。<br />
	4、Guice在2.0版本中提供了对AOP的支持，就像其他IOC容器做的那样。但是，我觉得AOP和IOC没什么联系，当初Spring做了两者，结果后来的IOC容器都多多少少提供了对AOP的支持。简单看了Guice的AOP介绍，只是实现了粗糙的拦截器模式。如果有对AOP的需要，选择Spring或者AspectJ才是王道。<br />
	5、目前Guice的最新版本是2.0,其网站http://code.google.com/p/google-guice有着较为详实的使用文档并且还有一些原理方面的介绍。并且，在其wiki给出的链接中竟然有关于Guice的图书，会有人买吗？</p>
<h3>3.4、实践经验</h3>
<p>	对Guice的使用，除了散落在各类中的注释，和Guice有关联的代码就是实现Moudle和使用Injector。对于实现Moudle，我原以为不同Moudle中的bind具有独立的作用域，但实践的效果是各Module configure的Binder应该是全局一个的（原理上可能并不如此）。所以，只需要实现一个Module绑定所有类型即可。这样，完全可以定义一个工厂，其只提供一个方法：<T> T newInstance(Class<T> c);，然后实现一个依赖于Guice的工厂类。如果将来需要迁移Guice到Spring或者手工创建，只需要换个实现工厂类即可。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/06/193.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Netty实现原理浅析</title>
		<link>http://www.kafka0102.com/2010/06/167.html</link>
		<comments>http://www.kafka0102.com/2010/06/167.html#comments</comments>
		<pubDate>Sat, 19 Jun 2010 20:21:20 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[framework]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[netty]]></category>
		<category><![CDATA[nio framework]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=167</guid>
		<description><![CDATA[Netty是JBoss出品的高效的Java NIO开发框架，关于其使用，可参考我的另一篇文章 netty使用初步。本文将主要分析Netty实现方面的东西，由于精力有限，本人并没有对其源码做了极细致的研 究。如果下面的内容有错误或不严谨的地方，也请指正和谅解。对于Netty使用者来说，Netty提供了几个典型的example，并有详尽的API doc和guide doc，本文的一些内容及图示也来自于Netty的文档，特此致谢。]]></description>
			<content:encoded><![CDATA[<p>Netty是JBoss出品的高效的Java  NIO开发框架，关于其使用，可参考我的另一篇文章<a href="http://www.kafka0102.com/2010/06/netty%E4%BD%BF%E7%94%A8%E5%88%9D%E6%AD%A5/" target="_blank"> netty使用初步</a>。本文将主要分析Netty实现方面的东西，由于精力有限，本人并没有对其源码做了极细致的研 究。如果下面的内容有错误或不严谨的地方，也请指正和谅解。对于Netty使用者来说，Netty提供了几个典型的example，并有详尽的API  doc和guide doc，本文的一些内容及图示也来自于Netty的文档，特此致谢。</p>
<h2>1、总体结构</h2>
<p style="text-align: left;"><a href="http://www.kafka0102.com/wp-content/uploads/2010/06/architecture.png"><img class="aligncenter size-full wp-image-168" title="architecture" src="http://www.kafka0102.com/wp-content/uploads/2010/06/architecture.png" alt="" width="605" height="287" /></a></p>
<p style="text-align: left;">先放上一张漂亮的Netty总体结构图，下面的内容也主要围绕该图上的一些核心功能做分析，但对如Container  Integration及Security Support等高级可选功能，本文不予分析。</p>
<h2>2、网络模型</h2>
<p>Netty是典型的Reactor模型结构，关于Reactor的详尽阐释，可参考POSA2,这里不做概念性的解释。而应用Java  NIO构建Reactor模式，Doug Lea（就是那位让人无限景仰的大爷）在“<a href="http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf" target="_blank">Scalable IO in  Java</a>”中给了很好的阐述。这里截取其PPT中经典的图例说明 Reactor模式的典型实现：</p>
<p>1、这是最简单的单Reactor单线程模型。Reactor线程是个多面手，负责多路分离套接字，Accept新连接，并分派请求到处理器链中。该模型 适用于处理器链中业务处理组件能快速完成的场景。不过，这种单线程模型不能充分利用多核资源，所以实际使用的不多。</p>
<p style="text-align: center;"><a href="http://www.kafka0102.com/wp-content/uploads/2010/06/reactor1.png"><img class="aligncenter size-full wp-image-170" title="reactor1" src="http://www.kafka0102.com/wp-content/uploads/2010/06/reactor1.png" alt="" width="470" height="256" /></a></p>
<p>2、相比上一种模型，该模型在处理器链部分采用了多线程（线程池），也是后端程序常用的模型。</p>
<p style="text-align: center;"><a href="http://www.kafka0102.com/wp-content/uploads/2010/06/reactor2.png"><img class="aligncenter size-full wp-image-172" title="reactor2" src="http://www.kafka0102.com/wp-content/uploads/2010/06/reactor2.png" alt="" width="582" height="395" /></a></p>
<p style="text-align: left;">3、 第三种模型比起第二种模型，是将Reactor分成两部分，mainReactor负责监听server  socket，accept新连接，并将建立的socket分派给subReactor。subReactor负责多路分离已连接的socket，读写网 络数据，对业务处理功能，其扔给worker线程池完成。通常，subReactor个数上可与CPU个数等同。<br />
<a href="http://www.kafka0102.com/wp-content/uploads/2010/06/reactor3.png"><img class="aligncenter size-full wp-image-173" title="reactor3" src="http://www.kafka0102.com/wp-content/uploads/2010/06/reactor3.png" alt="" width="573" height="389" /></a></p>
<p>说完Reacotr模型的三种形式，那么Netty是哪种呢？其实，我还有一种Reactor模型的变种没说，那就是去掉线程池的第三种形式的变种，这也 是Netty  NIO的默认模式。在实现上，Netty中的Boss类充当mainReactor，NioWorker类充当subReactor（默认 NioWorker的个数是Runtime.getRuntime().availableProcessors()）。在处理新来的请求 时，NioWorker读完已收到的数据到ChannelBuffer中，之后触发ChannelPipeline中的ChannelHandler流。</p>
<p>Netty是事件驱动的，可以通过ChannelHandler链来控制执行流向。因为ChannelHandler链的执行过程是在 subReactor中同步的，所以如果业务处理handler耗时长，将严重影响可支持的并发数。这种模型适合于像Memcache这样的应用场景，但 对需要操作数据库或者和其他模块阻塞交互的系统就不是很合适。Netty的可扩展性非常好，而像ChannelHandler线程池化的需要，可以通过在 ChannelPipeline中添加Netty内置的ChannelHandler实现类&#8211;ExecutionHandler实现，对使用者来说只是 添加一行代码而已。对于ExecutionHandler需要的线程池模型，Netty提供了两种可 选：1） MemoryAwareThreadPoolExecutor 可控制Executor中待处理任务的上限（超过上限时，后续进来的任务将被阻 塞），并可控制单个Channel待处理任务的上限；2） OrderedMemoryAwareThreadPoolExecutor 是  MemoryAwareThreadPoolExecutor 的子类，它还可以保证同一Channel中处理的事件流的顺序性，这主要是控制事件在异步处 理模式下可能出现的错误的事件顺序，但它并不保证同一Channel中的事件都在一个线程中执行（通常也没必要）。一般来 说，OrderedMemoryAwareThreadPoolExecutor 是个很不错的选择，当然，如果有需要，也可以DIY一个。</p>
<h2>3、 buffer</h2>
<p>org.jboss.netty.buffer包的接口及类的结构图如下：</p>
<p style="text-align: center;"><a href="http://www.kafka0102.com/wp-content/uploads/2010/06/channelbuffer.png"><img class="aligncenter size-full wp-image-174" title="channelbuffer" src="http://www.kafka0102.com/wp-content/uploads/2010/06/channelbuffer.png" alt="" width="801" height="384" /></a></p>
<p>该包核心的接口是ChannelBuffer和ChannelBufferFactory,下面予以简要的介绍。</p>
<p>Netty使用ChannelBuffer来存储并操作读写的网络数据。ChannelBuffer除了提供和ByteBuffer类似的方法，还提供了 一些实用方法，具体可参考其API文档。ChannelBuffer的实现类有多个，这里列举其中主要的几个：</p>
<p>1）HeapChannelBuffer：这是Netty读网络数据时默认使用的ChannelBuffer，这里的Heap就是Java堆的意思，因为 读SocketChannel的数据是要经过ByteBuffer的，而ByteBuffer实际操作的就是个byte数组，所以 ChannelBuffer的内部就包含了一个byte数组，使得ByteBuffer和ChannelBuffer之间的转换是零拷贝方式。根据网络字 节续的不同，HeapChannelBuffer又分为BigEndianHeapChannelBuffer和 LittleEndianHeapChannelBuffer，默认使用的是BigEndianHeapChannelBuffer。Netty在读网络 数据时使用的就是HeapChannelBuffer，HeapChannelBuffer是个大小固定的buffer，为了不至于分配的Buffer的 大小不太合适，Netty在分配Buffer时会参考上次请求需要的大小。</p>
<p>2）DynamicChannelBuffer：相比于HeapChannelBuffer，DynamicChannelBuffer可动态自适应大 小。对于在DecodeHandler中的写数据操作，在数据大小未知的情况下，通常使用DynamicChannelBuffer。</p>
<p>3）ByteBufferBackedChannelBuffer：这是directBuffer，直接封装了ByteBuffer的 directBuffer。</p>
<p>对于读写网络数据的buffer，分配策略有两种：1）通常出于简单考虑，直接分配固定大小的buffer，缺点是，对一些应用来说这个大小限制有时是不 合理的，并且如果buffer的上限很大也会有内存上的浪费。2）针对固定大小的buffer缺点，就引入动态buffer，动态buffer之于固定 buffer相当于List之于Array。</p>
<p>buffer的寄存策略常见的也有两种（其实是我知道的就限于此）：1）在多线程（线程池） 模型下，每个线程维护自己的读写buffer，每次处理新的请求前清空buffer（或者在处理结束后清空），该请求的读写操作都需要在该线程中完成。 2）buffer和socket绑定而与线程无关。两种方法的目的都是为了重用buffer。</p>
<p>Netty对buffer的处理策略是：读 请求数据时，Netty首先读数据到新创建的固定大小的HeapChannelBuffer中，当HeapChannelBuffer满或者没有数据可读 时，调用handler来处理数据，这通常首先触发的是用户自定义的DecodeHandler，因为handler对象是和ChannelSocket 绑定的，所以在DecodeHandler里可以设置ChannelBuffer成员，当解析数据包发现数据不完整时就终止此次处理流程，等下次读事件触 发时接着上次的数据继续解析。就这个过程来说，和ChannelSocket绑定的DecodeHandler中的Buffer通常是动态的可重用 Buffer（DynamicChannelBuffer），而在NioWorker中读ChannelSocket中的数据的buffer是临时分配的 固定大小的HeapChannelBuffer，这个转换过程是有个字节拷贝行为的。</p>
<p>对ChannelBuffer的创建，Netty内部使用的是ChannelBufferFactory接口，具体的实现有 DirectChannelBufferFactory和HeapChannelBufferFactory。对于开发者创建 ChannelBuffer，可使用实用类ChannelBuffers中的工厂方法。</p>
<h2>4、Channel</h2>
<p>和Channel相关的接口及类结构图如下：</p>
<p><a href="http://www.kafka0102.com/wp-content/uploads/2010/06/Channel.png"><img class="aligncenter size-full wp-image-175" title="Channel" src="http://www.kafka0102.com/wp-content/uploads/2010/06/Channel.png" alt="" width="539" height="253" /></a></p>
<p>从该结构图也可以看到，Channel主要提供的功能如下：</p>
<p>1）当前Channel的状态信息，比如是打开还是关闭等。<br />
2）通过ChannelConfig可以得到的Channel配置信息。<br />
3）Channel所支持的如read、write、bind、connect等IO操作。<br />
4）得到处理该Channel的ChannelPipeline，既而可以调用其做和请求相关的IO操作。</p>
<p>在Channel实现方面，以通常使用的nio  socket来说，Netty中的NioServerSocketChannel和NioSocketChannel分别封装了java.nio中包含的 ServerSocketChannel和SocketChannel的功能。</p>
<h2>5、ChannelEvent</h2>
<p>如前所述，Netty是事件驱动的，其通过ChannelEvent来确定事件流的方向。一个ChannelEvent是依附于Channel的 ChannelPipeline来处理，并由ChannelPipeline调用ChannelHandler来做具体的处理。下面是和 ChannelEvent相关的接口及类图：</p>
<p><a href="http://www.kafka0102.com/wp-content/uploads/2010/06/ChannelEvent.png"><img class="aligncenter size-full wp-image-176" title="ChannelEvent" src="http://www.kafka0102.com/wp-content/uploads/2010/06/ChannelEvent.png" alt="" width="416" height="437" /></a></p>
<p>对于使用者来说，在ChannelHandler实现类中会使用继承于ChannelEvent的MessageEvent，调用其 getMessage()方法来获得读到的ChannelBuffer或被转化的对象。</p>
<h2>6、ChannelPipeline</h2>
<p>Netty 在事件处理上，是通过ChannelPipeline来控制事件流，通过调用注册其上的一系列ChannelHandler来处理事件，这也是典型的拦截 器模式。下面是和ChannelPipeline相关的接口及类图：</p>
<p><a href="http://www.kafka0102.com/wp-content/uploads/2010/06/ChannelPipeline.png"><img class="aligncenter size-full wp-image-177" title="ChannelPipeline" src="http://www.kafka0102.com/wp-content/uploads/2010/06/ChannelPipeline.png" alt="" width="559" height="237" /></a></p>
<p>事件流有两种，upstream事件和downstream事件。在ChannelPipeline中，其可被注册的ChannelHandler既可以 是 ChannelUpstreamHandler 也可以是ChannelDownstreamHandler  ，但事件在ChannelPipeline传递过程中只会调用匹配流的ChannelHandler。在事件流的过滤器链 中，ChannelUpstreamHandler或ChannelDownstreamHandler既可以终止流程，也可以通过调用 ChannelHandlerContext.sendUpstream(ChannelEvent)或 ChannelHandlerContext.sendDownstream(ChannelEvent)将事件传递下去。下面是事件流处理的图示：</p>
<p><a href="http://www.kafka0102.com/wp-content/uploads/2010/06/ChannelPipeline.jpg"><img class="aligncenter size-full wp-image-178" title="ChannelPipeline" src="http://www.kafka0102.com/wp-content/uploads/2010/06/ChannelPipeline.jpg" alt="" width="522" height="622" /></a></p>
<p>从上图可见，upstream event是被Upstream Handler们自底向上逐个处理，downstream  event是被Downstream  Handler们自顶向下逐个处理，这里的上下关系就是向ChannelPipeline里添加Handler的先后顺序关系。简单的理 解，upstream event是处理来自外部的请求的过程，而downstream event是处理向外发送请求的过程。</p>
<p>服务端处 理请求的过程通常就是解码请求、业务逻辑处理、编码响应，构建的ChannelPipeline也就类似下面的代码片断：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">ChannelPipeline pipeline <span style="color: #339933;">=</span> Channels.<span style="color: #006633;">pipeline</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
pipeline.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;decoder&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> MyProtocolDecoder<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
pipeline.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;encoder&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> MyProtocolEncoder<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
pipeline.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;handler&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> MyBusinessLogicHandler<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>其中，MyProtocolDecoder是ChannelUpstreamHandler类型，MyProtocolEncoder是 ChannelDownstreamHandler类型，MyBusinessLogicHandler既可以是 ChannelUpstreamHandler类型，也可兼ChannelDownstreamHandler类型，视其是服务端程序还是客户端程序以及 应用需要而定。</p>
<p>补充一点，Netty对抽象和实现做了很好的解耦。像org.jboss.netty.channel.socket包， 定义了一些和socket处理相关的接口，而org.jboss.netty.channel.socket.nio、 org.jboss.netty.channel.socket.oio等包，则是和协议相关的实现。</p>
<h2>7、codec  framework</h2>
<p>对于请求协议的编码解码，当然是可以按照协议格式自己操作ChannelBuffer中的字节数据。另一方面，Netty也做了几个很实用的codec  helper，这里给出简单的介绍。</p>
<p>1）FrameDecoder：FrameDecoder内部维护了一个 DynamicChannelBuffer成员来存储接收到的数据，它就像个抽象模板，把整个解码过程模板写好了，其子类只需实现decode函数即可。 FrameDecoder的直接实现类有两个：（1）DelimiterBasedFrameDecoder是基于分割符  （比如\r\n）的解码器，可在构造函数中指定分割符。（2）LengthFieldBasedFrameDecoder是基于长度字段的解码器。如果协 议 格式类似“内容长度”+内容、“固定头”+“内容长度”+动态内容这样的格式，就可以使用该解码器，其使用方法在API DOC上详尽的解释。<br />
2）ReplayingDecoder： 它是FrameDecoder的一个变种子类，它相对于FrameDecoder是非阻塞解码。也就是说，使用  FrameDecoder时需要考虑到读到的数据有可能是不完整的，而使用ReplayingDecoder就可以假定读到了全部的数据。<br />
3）ObjectEncoder 和ObjectDecoder：编码解码序列化的Java对象。<br />
4）HttpRequestEncoder和 HttpRequestDecoder：http协议处理。</p>
<p>下面来看使用FrameDecoder和ReplayingDecoder的两个例子：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> IntegerHeaderFrameDecoder <span style="color: #000000; font-weight: bold;">extends</span> FrameDecoder <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #003399;">Object</span> decode<span style="color: #009900;">&#40;</span>ChannelHandlerContext ctx, Channel channel,
				ChannelBuffer buf<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>buf.<span style="color: #006633;">readableBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
			buf.<span style="color: #006633;">markReaderIndex</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #000066; font-weight: bold;">int</span> length <span style="color: #339933;">=</span> buf.<span style="color: #006633;">readInt</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>buf.<span style="color: #006633;">readableBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span> length<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
				buf.<span style="color: #006633;">resetReaderIndex</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
				<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
			<span style="color: #009900;">&#125;</span>
			<span style="color: #000000; font-weight: bold;">return</span> buf.<span style="color: #006633;">readBytes</span><span style="color: #009900;">&#40;</span>length<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<p>而使用ReplayingDecoder的解码片断类似下面的，相对来说会简化很多。</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> IntegerHeaderFrameDecoder2 <span style="color: #000000; font-weight: bold;">extends</span> ReplayingDecoder <span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #003399;">Object</span> decode<span style="color: #009900;">&#40;</span>ChannelHandlerContext ctx, Channel channel,
				ChannelBuffer buf, VoidEnum state<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #000000; font-weight: bold;">return</span> buf.<span style="color: #006633;">readBytes</span><span style="color: #009900;">&#40;</span>buf.<span style="color: #006633;">readInt</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<p>就实现来说，当在ReplayingDecoder子类的decode函数中调用ChannelBuffer读数据时，如果读失败，那么 ReplayingDecoder就会catch住其抛出的Error，然后ReplayingDecoder接手控制权，等待下一次读到后续的数据后继 续decode。</p>
<h2>8、小结</h2>
<p>尽管该文行至此处将止，但该文显然没有将Netty实现原理深入浅出的说全说透。当我打算写这篇文章时，也是一边看Netty的代码，一边总结些可写的东 西，但前后断断续续，到最后都没了多少兴致。我还是爱做一些源码分析的事情，但精力终究有限，并且倘不能把源码分析的结果有条理的托出来，不能产生有意义 的心得，这分析也没什么价值和趣味。而就分析Netty代码的感受来说，Netty的代码很漂亮，结构上层次上很清晰，不过这种面向接口及抽象层次对代码 跟踪很是个问题，因为跟踪代码经常遇到接口和抽象类，只能借助于工厂类和API  DOC，反复对照接口和实现类的对应关系。就像几乎任何优秀的Java开源项目都会用上一系列优秀的设计模式，也完全可以从模式这一点单独拿出一篇分析文 章来，尽管我目前没有这样的想法。而在此文完成之后，我也没什么兴趣再看Netty的代码了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/06/167.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Netty使用初步</title>
		<link>http://www.kafka0102.com/2010/06/161.html</link>
		<comments>http://www.kafka0102.com/2010/06/161.html#comments</comments>
		<pubDate>Sat, 19 Jun 2010 16:32:15 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[framework]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[netty]]></category>
		<category><![CDATA[nio framework]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=161</guid>
		<description><![CDATA[    Java1.4提供了NIO使开发者可以使用Java编写高性能的服务端程序，但使用原生的NIO API就像Linux C中网络编程一样，还是需要做IO处理、协议处理等低层次工作。所以，就像C服务端程序大量使用libevent作为网络应用框架一样，Java社区也不断涌现出基于NIO的网络应用框架。在这其中，Jboss出品的Netty就是个中翘楚。Netty是个异步的事件驱动网络应用框架，具有高性能、高扩展性等特性。Netty提供了统一的底层协议接口，使得开发者从底层的网络协议（比如TCP/IP、UDP）中解脱出来。就使用来说，开发者只要参考 Netty提供的若干例子和它的指南文档，就可以放手开发基于Netty的服务端程序了。
    在Java社区，最知名的开源Java NIO框架要属Mina和Netty，而且两者渊源颇多，对两者的比较自然不少。实际上，Netty的作者原来就是Mina作者之一，所以可以想到，Netty和Mina在设计理念上会有很多共同点。我对Mina没什么研究，但其作者介绍，Netty的设计对开发者有更友好的扩展性，并且性能方面要优于Mina，而Netty完善的文档也很吸引人。所以，如果你在寻找Java NIO框架，Netty是个很不错的选择。本文的内容就是围绕一个demo介绍使用Netty的点点滴滴。]]></description>
			<content:encoded><![CDATA[<h2>1、简介</h2>
<p>    Java1.4提供了NIO使开发者可以使用Java编写高性能的服务端程序，但使用原生的NIO API就像Linux C中网络编程一样，还是需要做IO处理、协议处理等低层次工作。所以，就像C服务端程序大量使用libevent作为网络应用框架一样，Java社区也不断涌现出基于NIO的网络应用框架。在这其中，Jboss出品的Netty就是个中翘楚。Netty是个异步的事件驱动网络应用框架，具有高性能、高扩展性等特性。Netty提供了统一的底层协议接口，使得开发者从底层的网络协议（比如TCP/IP、UDP）中解脱出来。就使用来说，开发者只要参考 Netty提供的若干例子和它的指南文档，就可以放手开发基于Netty的服务端程序了。</p>
<p>    在Java社区，最知名的开源Java NIO框架要属Mina和Netty，而且两者渊源颇多，对两者的比较自然不少。实际上，Netty的作者原来就是Mina作者之一，所以可以想到，Netty和Mina在设计理念上会有很多共同点。我对Mina没什么研究，但其作者介绍，Netty的设计对开发者有更友好的扩展性，并且性能方面要优于Mina，而Netty完善的文档也很吸引人。所以，如果你在寻找Java NIO框架，Netty是个很不错的选择。本文的内容就是围绕一个demo介绍使用Netty的点点滴滴。</p>
<h2>2、服务端程序</h2>
<h3>2.1、ChannelHandler</h3>
<p>     服务端程序通常的处理过程是：解码请求数据、业务逻辑处理、编码响应。从框架角度来说，可以提供3个接口来控制并调度该处理过程；从更通用的角度来说，并不特化处理其中的每一步，而把每一步当做过滤器链中的一环，这也是Netty的做法。Netty对请求处理过程实现了过滤器链模式（ChannelPipeline），每个过滤器实现了ChannelHandler接口。Netty中有两种请求事件流类型也做了细分：</p>
<p>    1）downstream event：其对应的ChannelHandler子接口是ChannelDownstreamHandler。downstream event是说从头到尾执行ChannelPipeline中的ChannelDownstreamHandler，这一过程相当于向外发送数据的过程。 downstream event有：&#8221;write&#8221;、&#8221;bind&#8221;、&#8221;unbind&#8221;、 &#8220;connect&#8221;、 &#8220;disconnect&#8221;、&#8221;close&#8221;。</p>
<p>    2）upstream event：其对应的ChannelHandler子接口是ChannelUpstreamHandler。upstream event处理的事件方向和downstream event相反，这一过程相当于接收处理外来请求的过程。upstream event有：&#8221;messageReceived&#8221;、 &#8220;exceptionCaught&#8221;、&#8221;channelOpen&#8221;、&#8221;channelClosed&#8221;、 &#8220;channelBound&#8221;、&#8221;channelUnbound&#8221;、 &#8220;channelConnected&#8221;、&#8221;writeComplete&#8221;、&#8221;channelDisconnected&#8221;、&#8221;channelInterestChanged&#8221;。</p>
<p>     Netty中有个注释@interface ChannelPipelineCoverage，它表示被注释的ChannelHandler是否能添加到多个ChannelPipeline中，其可选的值是&#8221;all&#8221;和&#8221;one&#8221;。&#8221;all&#8221;表示ChannelHandler是无状态的，可被多个ChannelPipeline共享，而&#8221;one&#8221;表示ChannelHandler只作用于单个ChannelPipeline中。但ChannelPipelineCoverage只是个注释而已，并没有实际的检查作用。对于ChannelHandler是&#8221;all&#8221;还是&#8221;one&#8221;，还是根据逻辑需要而定。比如，像解码请求handler，因为可能解码的数据不完整，需要等待下一次读事件来了之后再继续解析，所以解码请求handler就需要是&#8221;one&#8221;的（否则多个Channel共享数据就乱了）。而像业务逻辑处理hanlder通常是&#8221;all&#8221;的。</p>
<p>     下面以一个简单的例子说明如何编写“解码请求数据、业务逻辑处理、编码响应”这一过程中涉及的ChannelHandler。该例子实现的协议格式很简单，请求和响应流中头4个字节表示后面跟的内容长度，根据该长度可得到内容体。</p>
<p>    首先看下解码器的实现：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MessageDecoder <span style="color: #000000; font-weight: bold;">extends</span> FrameDecoder <span style="color: #009900;">&#123;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #003399;">Object</span> decode<span style="color: #009900;">&#40;</span>
            ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>buffer.<span style="color: #006633;">readableBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//(1)</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000066; font-weight: bold;">int</span> dataLength <span style="color: #339933;">=</span> buffer.<span style="color: #006633;">getInt</span><span style="color: #009900;">&#40;</span>buffer.<span style="color: #006633;">readerIndex</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>buffer.<span style="color: #006633;">readableBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> dataLength <span style="color: #339933;">+</span> <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//(2)</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        buffer.<span style="color: #006633;">skipBytes</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//(3)</span>
        <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> decoded <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span>dataLength<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        buffer.<span style="color: #006633;">readBytes</span><span style="color: #009900;">&#40;</span>decoded<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #003399;">String</span> msg <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#40;</span>decoded<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//(4)</span>
        <span style="color: #000000; font-weight: bold;">return</span> msg<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>    MessageDecoder继承自FrameDecoder，FrameDecoder是Netty codec包中的辅助类，它是个ChannelUpstreamHandler，decode方法是FrameDecoder子类需要实现的。在上面的代码中，有：</p>
<p>    (1)检查ChannelBuffer中的字节数，如果ChannelBuffer可读的字节数少于4,则返回null等待下次读事件。<br />
    (2)继续检查ChannelBuffer中的字节数，如果ChannelBuffer可读的字节数少于dataLength + 4，则返回null等待下次读事件。<br />
    (3)越过dataLength的字节。<br />
    (4)构造解码的字符串返回。</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@ChannelPipelineCoverage<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;all&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MessageServerHandler <span style="color: #000000; font-weight: bold;">extends</span> SimpleChannelUpstreamHandler <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> Logger logger <span style="color: #339933;">=</span> Logger.<span style="color: #006633;">getLogger</span><span style="color: #009900;">&#40;</span>
            MessageServerHandler.<span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> messageReceived<span style="color: #009900;">&#40;</span>
            ChannelHandlerContext ctx, MessageEvent e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span>e.<span style="color: #006633;">getMessage</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">instanceof</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">return</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//(1)</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #003399;">String</span> msg <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#41;</span> e.<span style="color: #006633;">getMessage</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #003399;">System</span>.<span style="color: #006633;">err</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;got msg:&quot;</span><span style="color: #339933;">+</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        e.<span style="color: #006633;">getChannel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">write</span><span style="color: #009900;">&#40;</span>msg<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//(2)</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> exceptionCaught<span style="color: #009900;">&#40;</span>
            ChannelHandlerContext ctx, ExceptionEvent e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        logger.<span style="color: #006633;">log</span><span style="color: #009900;">&#40;</span>
                Level.<span style="color: #006633;">WARNING</span>,
                <span style="color: #0000ff;">&quot;Unexpected exception from downstream.&quot;</span>,
                e.<span style="color: #006633;">getCause</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        e.<span style="color: #006633;">getChannel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>    MessageServerHandler是服务端业务处理handler，其继承自SimpleChannelUpstreamHandler，并主要实现messageReceived事件。关于该类，有如下注解：</p>
<p>    (1)该upstream事件流中，首先经过MessageDecoder，其会将decode返回的解码后的数据构造成 MessageEvent.getMessage()，所以在handler上下文关系中，MessageEvent.getMessage()并不一定都返回ChannelBuffer类型的数据。<br />
    (2)MessageServerHandler只是简单的将得到的msg再写回给客户端。e.getChannel().write(msg);操作将触发DownstreamMessageEvent事件，也就是调用下面的MessageEncoder将编码的数据返回给客户端。</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@ChannelPipelineCoverage<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;all&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MessageEncoder <span style="color: #000000; font-weight: bold;">extends</span> OneToOneEncoder <span style="color: #009900;">&#123;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #003399;">Object</span> encode<span style="color: #009900;">&#40;</span>
            ChannelHandlerContext ctx, Channel channel, <span style="color: #003399;">Object</span> msg<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span>msg <span style="color: #000000; font-weight: bold;">instanceof</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">return</span> msg<span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//(1)</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #003399;">String</span> res <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#41;</span>msg<span style="color: #339933;">;</span>
        <span style="color: #000066; font-weight: bold;">byte</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> data <span style="color: #339933;">=</span> res.<span style="color: #006633;">getBytes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000066; font-weight: bold;">int</span> dataLength <span style="color: #339933;">=</span> data.<span style="color: #006633;">length</span><span style="color: #339933;">;</span>
        ChannelBuffer buf <span style="color: #339933;">=</span> ChannelBuffers.<span style="color: #006633;">dynamicBuffer</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//(2)</span>
        buf.<span style="color: #006633;">writeInt</span><span style="color: #009900;">&#40;</span>dataLength<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        buf.<span style="color: #006633;">writeBytes</span><span style="color: #009900;">&#40;</span>data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">return</span> buf<span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//(3)</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>    MessageEncoder是个ChannelDownstreamHandler。对该类的注解如下：</p>
<p>    (1)如果编码的msg不是合法类型，就直接返回该msg，之后OneToOneEncoder会调用 ctx.sendDownstream(evt);来调用下一个ChannelDownstreamHandler。对于该例子来说，这种情况是不应该出现的。<br />
    (2)开发者创建ChannelBuffer的用武之地就是这儿了，通常使用dynamicBuffer即可，表示得到的ChannelBuffer可动态增加大小。<br />
    (3)返回编码后的ChannelBuffer之后，OneToOneEncoder会调用Channels.write将数据写回客户端。</p>
<h3>2.2、MessageServerPipelineFactory</h3>
<p>    创建了3个ChannelHandler，需要将他们注册到ChannelPipeline，而ChannelPipeline又是和Channel对应的（是全局单例还是每个Channel对应一个ChannelPipeline实例依赖于实现）。可以实现ChannelPipeline的工厂接口 ChannelPipelineFactory实现该目的。MessageServerPipelineFactory的代码如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MessageServerPipelineFactory <span style="color: #000000; font-weight: bold;">implements</span>
        ChannelPipelineFactory <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> ChannelPipeline getPipeline<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
        ChannelPipeline pipeline <span style="color: #339933;">=</span> pipeline<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        pipeline.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;decoder&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> MessageDecoder<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        pipeline.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;encoder&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> MessageEncoder<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        pipeline.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;handler&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> MessageServerHandler<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">return</span> pipeline<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<h3>2.3、MessageServer</h3>
<p>    服务端程序就剩下启动代码了，使用Netty的ServerBootstrap三下五除二完成之。</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MessageServer <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Configure the server.</span>
        ServerBootstrap bootstrap <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ServerBootstrap<span style="color: #009900;">&#40;</span>
                <span style="color: #000000; font-weight: bold;">new</span> NioServerSocketChannelFactory<span style="color: #009900;">&#40;</span>
                        Executors.<span style="color: #006633;">newCachedThreadPool</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,
                        Executors.<span style="color: #006633;">newCachedThreadPool</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Set up the default event pipeline.</span>
        bootstrap.<span style="color: #006633;">setPipelineFactory</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> MessageServerPipelineFactory<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Bind and start to accept incoming connections.</span>
        bootstrap.<span style="color: #006633;">bind</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> InetSocketAddress<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">8080</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>    稍加补充的是，该Server程序并不完整，它没有处理关闭时的资源释放，尽管暴力的来看并不一定需要做这样的善后工作。</p>
<h2>3、客户端程序</h2>
<p>    客户端程序和服务端程序处理模型上是很相似的，这里还是付上代码并作简要说明。</p>
<h3>3.1、 ChannelHandler</h3>
<p>    客户端是先发送数据到服务端（downstream事件流），然后是处理从服务端接收的数据（upstream事件流）。这里有个问题是，怎么把需要发送的数据送到downstream事件流里呢？这就用到了ChannelUpstreamHandler的channelConnected事件了。实现的 MessageClientHandler代码如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">@ChannelPipelineCoverage<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;all&quot;</span><span style="color: #009900;">&#41;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MessageClientHandler <span style="color: #000000; font-weight: bold;">extends</span> SimpleChannelUpstreamHandler <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">final</span> Logger logger <span style="color: #339933;">=</span> Logger.<span style="color: #006633;">getLogger</span><span style="color: #009900;">&#40;</span>
            MessageClientHandler.<span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> channelConnected<span style="color: #009900;">&#40;</span>
            ChannelHandlerContext ctx, ChannelStateEvent e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003399;">String</span> message <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;hello kafka0102&quot;</span><span style="color: #339933;">;</span>
        e.<span style="color: #006633;">getChannel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">write</span><span style="color: #009900;">&#40;</span>message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> messageReceived<span style="color: #009900;">&#40;</span>
            ChannelHandlerContext ctx, MessageEvent e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Send back the received message to the remote peer.</span>
        <span style="color: #003399;">System</span>.<span style="color: #006633;">err</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;messageReceived send message &quot;</span><span style="color: #339933;">+</span>e.<span style="color: #006633;">getMessage</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #003399;">Thread</span>.<span style="color: #006633;">sleep</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1000</span><span style="color: #339933;">*</span><span style="color: #cc66cc;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">Exception</span> ex<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            ex.<span style="color: #006633;">printStackTrace</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        e.<span style="color: #006633;">getChannel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">write</span><span style="color: #009900;">&#40;</span>e.<span style="color: #006633;">getMessage</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> exceptionCaught<span style="color: #009900;">&#40;</span>
            ChannelHandlerContext ctx, ExceptionEvent e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Close the connection when an exception is raised.</span>
        logger.<span style="color: #006633;">log</span><span style="color: #009900;">&#40;</span>
                Level.<span style="color: #006633;">WARNING</span>,
                <span style="color: #0000ff;">&quot;Unexpected exception from downstream.&quot;</span>,
                e.<span style="color: #006633;">getCause</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        e.<span style="color: #006633;">getChannel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>    对于编码和解码Handler，复用MessageEncoder和MessageDecoder即可。</p>
<h3>3.2、 MessageClientPipelineFactory</h3>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MessageClientPipelineFactory <span style="color: #000000; font-weight: bold;">implements</span>
        ChannelPipelineFactory <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> ChannelPipeline getPipeline<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
        ChannelPipeline pipeline <span style="color: #339933;">=</span> pipeline<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        pipeline.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;decoder&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> MessageDecoder<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        pipeline.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;encoder&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> MessageEncoder<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        pipeline.<span style="color: #006633;">addLast</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;handler&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> MessageClientHandler<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">return</span> pipeline<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<h3>3.3、MessageClient</h3>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MessageClient <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> main<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> args<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Parse options.</span>
        <span style="color: #003399;">String</span> host <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;127.0.0.1&quot;</span><span style="color: #339933;">;</span>
        <span style="color: #000066; font-weight: bold;">int</span> port <span style="color: #339933;">=</span> <span style="color: #cc66cc;">8080</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// Configure the client.</span>
        ClientBootstrap bootstrap <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ClientBootstrap<span style="color: #009900;">&#40;</span>
                <span style="color: #000000; font-weight: bold;">new</span> NioClientSocketChannelFactory<span style="color: #009900;">&#40;</span>
                        Executors.<span style="color: #006633;">newCachedThreadPool</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>,
                        Executors.<span style="color: #006633;">newCachedThreadPool</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// Set up the event pipeline factory.</span>
        bootstrap.<span style="color: #006633;">setPipelineFactory</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> MessageClientPipelineFactory<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// Start the connection attempt.</span>
        ChannelFuture future <span style="color: #339933;">=</span> bootstrap.<span style="color: #006633;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> InetSocketAddress<span style="color: #009900;">&#40;</span>host, port<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// Wait until the connection is closed or the connection attempt fails.</span>
        future.<span style="color: #006633;">getChannel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getCloseFuture</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">awaitUninterruptibly</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// Shut down thread pools to exit.</span>
        bootstrap.<span style="color: #006633;">releaseExternalResources</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>    在写客户端例子时，我想像的代码并不是这样的，对客户端的代码我也没做过多的研究，所以也可能没有找到更好的解决方案。在上面的例子中，bootstrap.connect方法中会触发实际的连接操作，接着触发 MessageClientHandler.channelConnected，使整个过程运转起来。但是，我想要的是一个连接池，并且如何写数据也不应该在channelConnected中，这样对于动态的数据，只能在构造函数中传递需要写的数据了。但到现在，我还不清楚如何将连接池和 ChannelPipeline有效的结合起来。或许，这样的需求可以跨过Netty来实现。</p>
<h2>4、总结</h2>
<p>    关于Netty的初步使用，尚且总结到这里。关于这篇文章，写得断断续续，以至于到后来我都没兴趣把内容都整理出来。当然，这多少也是因为我是先整理 Netty原理方面的东西所致。我也只能卑微的期望，该文对Netty入门者会有些许帮助。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/06/161.html/feed</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>在Java中使用脚本语言</title>
		<link>http://www.kafka0102.com/2010/06/155.html</link>
		<comments>http://www.kafka0102.com/2010/06/155.html#comments</comments>
		<pubDate>Sun, 06 Jun 2010 07:45:57 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[ScriptEngine]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=155</guid>
		<description><![CDATA[    有一段时间没有搞Java，对于Java5以来一些新特性了解也不多，这几天看Solr的DIH，发现个很不错的配置支持--脚本引擎。以前提Java，是一处编译到处运行，现在可以说是一个平台多种语言。借此机会，整理了下Java6中引入的脚本引擎的相关特点和功能]]></description>
			<content:encoded><![CDATA[<p>    有一段时间没有搞Java，对于Java5以来一些新特性了解也不多，这几天看Solr的DIH，发现个很不错的配置支持&#8211;脚本引擎。以前提Java，是一处编译到处运行，现在可以说是一个平台多种语言。借此机会，整理了下Java6中引入的脚本引擎的相关特点和功能。</p>
<h2>1、可用的脚本引擎</h2>
<p>    Java6提供对执行脚本语言的支持，这个支持来自于JSR223规范，对应的包是javax.script。默认情况下，Java6只支持 JavaScript脚本，它底层的实现是Mozilla Rhino（Rhino意为犀牛，是不是想起那本JavaScript大部头的封面了？），它是个纯Java的JavaScript实现。可以通过下面的代码列出当前环境中支持的脚本引擎：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">        ScriptEngineManager manager <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ScriptEngineManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        List<span style="color: #339933;">&lt;</span>ScriptEngineFactory<span style="color: #339933;">&gt;</span> factories <span style="color: #339933;">=</span> manager.<span style="color: #006633;">getEngineFactories</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span>ScriptEngineFactory f <span style="color: #339933;">:</span> factories<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>
                    <span style="color: #0000ff;">&quot;egine name:&quot;</span><span style="color: #339933;">+</span>f.<span style="color: #006633;">getEngineName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>
                    <span style="color: #0000ff;">&quot;,engine version:&quot;</span><span style="color: #339933;">+</span>f.<span style="color: #006633;">getEngineVersion</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>
                    <span style="color: #0000ff;">&quot;,language name:&quot;</span><span style="color: #339933;">+</span>f.<span style="color: #006633;">getLanguageName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>
                    <span style="color: #0000ff;">&quot;,language version:&quot;</span><span style="color: #339933;">+</span>f.<span style="color: #006633;">getLanguageVersion</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>
                    <span style="color: #0000ff;">&quot;,names:&quot;</span><span style="color: #339933;">+</span>f.<span style="color: #006633;">getNames</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>
                    <span style="color: #0000ff;">&quot;,mime:&quot;</span><span style="color: #339933;">+</span>f.<span style="color: #006633;">getMimeTypes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>
                    <span style="color: #0000ff;">&quot;,extension:&quot;</span><span style="color: #339933;">+</span>f.<span style="color: #006633;">getExtensions</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span></pre></div></div>

<p>    在我的机器上的输出是：egine name:Mozilla Rhino,engine version:1.6 release 2,language name:ECMAScript,language version:1.6,names:[js, rhino, JavaScript, javascript, ECMAScript, ecmascript],mime:[application/javascript, application/ecmascript, text/javascript, text/ecmascript],extension:[js]。可以看到，Java内置只支持JavaScript一种脚本。但是，只要遵循 JSR223，便可以扩展支持多种脚本语言，可以从https://scripting.dev.java.net/上查找当前已被支持的脚本的第三方库。</p>
<h2>2、hello script</h2>
<p>    接下来给出在Java中使用JavaScript的Hello world示例：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">        ScriptEngineManager manager <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ScriptEngineManager <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        ScriptEngine engine <span style="color: #339933;">=</span> manager.<span style="color: #006633;">getEngineByName</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;js&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #003399;">String</span> script <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;print ('hello script')&quot;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            engine.<span style="color: #006633;">eval</span> <span style="color: #009900;">&#40;</span>script<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span>ScriptException e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            e.<span style="color: #006633;">printStackTrace</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span></pre></div></div>

<p>    使用的API还是很简单的，ScriptEngineManager是ScriptEngine的工厂，实例化该工厂的时候会加载可用的所有脚本引擎。从工厂中创建ScriptEngine可以使用getEngineByName、getEngineByExtension或 getEngineByMimeType来得到，只要参数名字能对上。执行脚本调用eval方法即可（效果等同于JavaScript中的eval）。</p>
<h2>3、传递变量</h2>
<p>    可以向脚本中传递变量，使得Java代码可以和脚本代码交互，示例如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">        ScriptEngineManager manager <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ScriptEngineManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        ScriptEngine engine <span style="color: #339933;">=</span> manager.<span style="color: #006633;">getEngineByName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;js&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        engine.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;a&quot;</span>, <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        engine.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;b&quot;</span>, <span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #003399;">Object</span> maxNum <span style="color: #339933;">=</span> engine.<span style="color: #006633;">eval</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;function max_num(a,b){return (a&gt;b)?a:b;}max_num(a,b);&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;max_num:&quot;</span> <span style="color: #339933;">+</span> maxNum<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            e.<span style="color: #006633;">printStackTrace</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span></pre></div></div>

<p>        输出内容：max_num:6</p>
<p>    对于上面put的变量，它作用于自身engine范围内，也就是ScriptContext.ENGINE_SCOPE，put 的变量放到一个叫Bindings的Map中，可以通过 engine.getBindings(ScriptContext.ENGINE_SCOPE).get(&#8220;a&#8221;);得到put的内容。和ENGINE_SCOPE相对，还有个ScriptContext.GLOBAL_SCOPE 作用域，其作用的变量是由同一ScriptEngineFactory创建的所有ScriptEngine共享的全局作用域。</p>
<h2>4、动态调用</h2>
<p>    上面的例子中定义了一个JavaScript函数max_num，可以通过Invocable接口来多次调用脚本库中的函数，Invocable接口是 ScriptEngine可选实现的接口。下面是个使用示例：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">        ScriptEngineManager manager <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ScriptEngineManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        ScriptEngine engine <span style="color: #339933;">=</span> manager.<span style="color: #006633;">getEngineByName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;js&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            engine.<span style="color: #006633;">eval</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;function max_num(a,b){return (a&gt;b)?a:b;}&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            Invocable invoke <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Invocable<span style="color: #009900;">&#41;</span> engine<span style="color: #339933;">;</span>
            <span style="color: #003399;">Object</span> maxNum <span style="color: #339933;">=</span> invoke.<span style="color: #006633;">invokeFunction</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;max_num&quot;</span>,<span style="color: #cc66cc;">4</span>,<span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>maxNum<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            maxNum <span style="color: #339933;">=</span> invoke.<span style="color: #006633;">invokeFunction</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;max_num&quot;</span>, <span style="color: #cc66cc;">7</span>,<span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>maxNum<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">// TODO: handle exception</span>
        <span style="color: #009900;">&#125;</span></pre></div></div>

<p>    上面的invokeFunction，第一个参数调用的脚本函数名，后面跟的可变参数是对应的脚本函数参数。</p>
<p>    Invocable还有个很酷的功能，就是动态实现接口，它可以从脚本引擎中得到Java Interface 的实例；也就是说，可以定义个一个Java接口，其实现是由脚本完成。以上面的例子为例，定义接口JSLib，该接口中的函数和JavaScript中的函数签名保持一致：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> JSLib <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">int</span> max_num<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> a,<span style="color: #000066; font-weight: bold;">int</span> b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>    调用示例：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">        ScriptEngineManager manager <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ScriptEngineManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        ScriptEngine engine <span style="color: #339933;">=</span> manager.<span style="color: #006633;">getEngineByName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;js&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            engine.<span style="color: #006633;">eval</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;function max_num(a,b){return (a&gt;b)?a:b;}&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            Invocable invoke <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Invocable<span style="color: #009900;">&#41;</span> engine<span style="color: #339933;">;</span>
            JSLib jslib <span style="color: #339933;">=</span> invoke.<span style="color: #006633;">getInterface</span><span style="color: #009900;">&#40;</span>JSLib.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000066; font-weight: bold;">int</span> maxNum <span style="color: #339933;">=</span> jslib.<span style="color: #006633;">max_num</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">4</span>,<span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>maxNum<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">// TODO: handle exception</span>
        <span style="color: #009900;">&#125;</span></pre></div></div>

<h2>5、使用 Java 对象</h2>
<p>    可以在JavaScript中使用Java代码，这确实是很酷的事情。在Rhino中，可以通过importClass导入一个类，也可以通过importPackage导入一个包，也可以直接使用全路经的类。在创建对象时，new也不是必须的。示例代码如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">        ScriptEngineManager manager <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ScriptEngineManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        ScriptEngine engine <span style="color: #339933;">=</span> manager.<span style="color: #006633;">getEngineByName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;js&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #003399;">String</span> script <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;var list = java.util.ArrayList();list.add(<span style="color: #000099; font-weight: bold;">\&quot;</span>kafka0102<span style="color: #000099; font-weight: bold;">\&quot;</span>);print(list.get(0));&quot;</span><span style="color: #339933;">;</span>
            engine.<span style="color: #006633;">eval</span><span style="color: #009900;">&#40;</span>script<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            e.<span style="color: #006633;">printStackTrace</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span></pre></div></div>

<h2>6、编译执行</h2>
<p>    脚本引擎默认是解释执行的，如果需要反复执行脚本，可以使用它的可选接口Compilable来编译执行脚本，以获得更好的性能，示例代码如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">        ScriptEngineManager manager <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ScriptEngineManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        ScriptEngine engine <span style="color: #339933;">=</span> manager.<span style="color: #006633;">getEngineByName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;js&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            Compilable compEngine <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Compilable<span style="color: #009900;">&#41;</span> engine<span style="color: #339933;">;</span>
            CompiledScript script <span style="color: #339933;">=</span> compEngine.<span style="color: #006633;">compile</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;function max_num(a,b){return (a&gt;b)?a:b;}&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            script.<span style="color: #006633;">eval</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            Invocable invoke <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Invocable<span style="color: #009900;">&#41;</span> engine<span style="color: #339933;">;</span>
            <span style="color: #003399;">Object</span> maxNum <span style="color: #339933;">=</span> invoke.<span style="color: #006633;">invokeFunction</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;max_num&quot;</span>,<span style="color: #cc66cc;">4</span>,<span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>maxNum<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            e.<span style="color: #006633;">printStackTrace</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span></pre></div></div>

<h2>7、总结</h2>
<p>    除了上面提到的特性，脚本引擎还有一些不错的功能，比如可以执行脚本文件，可以由多线程异步执行脚本等功能。引入脚本引擎，可以对一些配置扩展和业务规则做更强大而灵活的支持，也方便使用者选择自己熟悉的脚本语言来编写业务规则等。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/06/155.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>log4j使用指南</title>
		<link>http://www.kafka0102.com/2010/05/147.html</link>
		<comments>http://www.kafka0102.com/2010/05/147.html#comments</comments>
		<pubDate>Mon, 31 May 2010 13:26:51 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[log]]></category>
		<category><![CDATA[log4j]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=147</guid>
		<description><![CDATA[log4j是Java中老牌的日志工具了，其强大的功能、简便的使用，使得开源项目中随处可见它的身影。即便jdk1.4中引入了logging功  能，log4j还是最受欢迎的日志工具。对log4j的使用者来说，使用log4j的API就那个几个打印日志函数，最需要关注的就是它的配置文件。不 过，很多人只是从网上找个配置样例把它跑起来，而没有更有效的使用log4j处理日志。这其实也不仅仅关乎log4j的使用，而是实际的如何有效的利用工 具来记录日志、分析日志和监控日志。]]></description>
			<content:encoded><![CDATA[<h2>1.Introduction</h2>
<p>log4j是Java中老牌的日志工具了，其强大的功能、简便的使用，使得开源项目中随处可见它的身影。即便jdk1.4中引入了logging功  能，log4j还是最受欢迎的日志工具。对log4j的使用者来说，使用log4j的API就那个几个打印日志函数，最需要关注的就是它的配置文件。不 过，很多人只是从网上找个配置样例把它跑起来，而没有更有效的使用log4j处理日志。这其实也不仅仅关乎log4j的使用，而是实际的如何有效的利用工 具来记录日志、分析日志和监控日志。</p>
<p>log4j核心的概念有logger、appender、layout和filter，下面将分别做介绍。对于这些概念，既可以通过配置文件体现出来， 也可以通过它的API体现处理。在使用上，关注配置文件的细节即可，而不需要关注log4j自身的API及实现方面的事情。尽管抛开配置文件，也可以使用 API来操纵配置，甚至可以扩展它，但log4j提供的功能已经很强大了，通常也不需要使用者做二次开发。为了整理出该文，我也是对log4j的实现做了 算不上深入的浏览，本文的内容主要参考log4j的参考手册及相关文章。对于log4j的配置，log4j支持java  properties文件和xml文件，本文在阐述相关配置内容采用了xml格式，因为Filter功能properties文件不能支持。</p>
<h2>2.Loggers</h2>
<p>log4j的Logger类提供的功能如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">package</span> <span style="color: #006699;">org.apache.log4j</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Logger <span style="color: #009900;">&#123;</span>
<span style="color: #666666; font-style: italic;">// Creation &amp; retrieval methods:</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> Logger getRootLogger<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> Logger getLogger<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// printing methods:</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> trace<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> debug<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> info<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> warn<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> error<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> fatal<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// generic printing method:</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> log<span style="color: #009900;">&#40;</span>Level l, <span style="color: #003399;">Object</span> message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>使用上，通常是在类中通过private static Logger logger =  Logger.getLogger(package.classname); 声明静态logger成员，打日志就是调用各level函数。 getLogger的参数是Logger的标识，并具有层次关系，比如“com.foo”是“com.foo.Bar”的父Logger。logger的 xml配置格式是：</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;!ELEMENT logger <span style="color: #66cc66;">&#40;</span>level?,appender-ref*<span style="color: #66cc66;">&#41;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;">&lt;!ATTLIST logger</span>
<span style="color: #009900;">name ID #REQUIRED</span>
<span style="color: #009900;">additivity <span style="color: #66cc66;">&#40;</span>true|false<span style="color: #66cc66;">&#41;</span> <span style="color: #ff0000;">&quot;true&quot;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&gt;</span></span></pre></div></div>

<p>其中，子元素level表示输出的最低级别（默认是debug），appender-ref则引用配置中的appender（可以是多个）；其属性 name是标识，additivity表示在层级关系中，是否向上查找，比如A是B的父logger，A的level是info，B没有指定level，当B的additivity为true，在B打日志时，发现B没有指定level，就向上查找到A并使用A的level，否则就屏蔽掉B的输出。</p>
<p>在logger层级中，最顶层的是root logger，可以通过getRootLogger()得到（尽管很少有人会这么做）。常见的配置中也就是配置root logger，那么在各个类中创建的logger会直接继承root logger的配置。</p>
<p>有时也可能需要对特定的logger做处理，比如我的模块中用到memcached client库，因为模块的level是debug，这使得memcached client库中的debug信息都会打出来，而我真的不是很关心它，所以就通过下面的配置关掉它：</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;logger</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;com.danga&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;level</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;info&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/logger<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>对于日志level，log4j支持通过继承Level类自定义Level，这在一些情景下或许会有帮助。比如，可以添加一个Level来表示和统计相关的日志。另外，像上面提到的例子，logger的level是可继承的，当子logger没有指定level时，它会使用其父logger的，并一直检查到root logger。</p>
<h2>3.Appenders</h2>
<p>appender表示要把日志输出到哪里去。在 log4j.dtd中，appender声明的格式如下：</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;!ELEMENT appender <span style="color: #66cc66;">&#40;</span>errorHandler?, param*, layout?, filter*, appender-ref*<span style="color: #66cc66;">&#41;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;">&lt;!ATTLIST appender</span>
<span style="color: #009900;">name ID #REQUIRED</span>
<span style="color: #009900;">class CDATA #REQUIRED</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&gt;</span></span></pre></div></div>

<p>一个样例如下：</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;appender</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;console&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.ConsoleAppender&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;Target&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;System.out&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.PatternLayout&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;ConversionPattern&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;%-5p %c{1} - %m%n&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/layout<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/appender<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>下面说明appender可能包含的子元素的含义：<br />
1）errorHandler：这是一个钩子，当appender出现异常时（比如layout无效），可以指定errorHandler来做些善后工作，一般是不需要配置它的。<br />
2）param：不同的appender有自己特定的参数选项，每一个param是key-value对，可以查看log4j API doc中的Appender实现类API说明，其中的加粗字体便是。<br />
3）layout：下面有说明。<br />
4）filter：下面有说明。<br />
5）appender-ref：appender也可以包含多个appender。</p>
<p>下面简要介绍常用的几个Appender：<br />
1、ConsoleAppender：ConsoleAppender是将日志打到控制台上，这在开发时观察日志会相比打到文件里更方便一些。它可用的 param元素只有Target，可选值是System.out和System.err，默认的是System.out，如果配成System.err，在eclipse的console会输出红色字体内容。如果想要把一个应用中的日志内容（包括非日志内容的异常信息）都输出到一个文件，也可以使用 ConsoleAppender，通过输出重定向把所有内容打到一个文件中去。</p>
<p>2、FileAppender：FileAppender就是把日志打到文件里，也是用的最多的，它可用的param元素如下：<br />
1）File：输出的文件路径。<br />
2）Append：打开日志文件的模式，默认true表示追加写，否则会清空文件已有内容。<br />
3）BufferedIO：默认为false，如果为true表示对Writer包装成 BufferedWriter，这种缓冲方式对服务端应用来说会带来性能问题。</p>
<p>3、DailyRollingFileAppender：DailyRollingFileAppender是FileAppender的升级版，它支持对日志做定期切割，这可以省去我们配置crontab定期执行脚本来切割日志，它可用的param元素如下：<br />
1）File：输出的文件路径。<br />
2）Append：打开日志文件的模式，默认true表示追加写， 否则会清空文件已有内容。<br />
3）DatePattern：DailyRollingFileAppender根据该参数来调度何时切割日志，这个日期格式与 SimpleDateFormat一致，可以做到按分时天周月等不同粒度切割日志。比如，“&#8217;.'yyyy-MM-dd”表示每天零点切割日志，假如日志文件名是foo.log，那么在2010-05-31零点执行切割后前一天的日志文件名是foo.log.2010-05-30，31号新的日志打到 foo.log。DailyRollingFileAppender日志切割的过程是：关闭打开的日志文件（foo.log）句柄，rename该日志文件（foo.log.2010-05-30），打开新创建的日志文件（foo.log）。</p>
<h2>4.Layouts</h2>
<p>layout表示日志输出的格式，log4j支持的layout有TTCCLayout, HTMLLayout, PatternLayout, SimpleLayout和XMLLayout，常用的是PatternLayout，性能最好的是SimpleLayout（因为它足够 simple）。PatternLayout支持的模式选项说明如下：</p>
<p>%m:输出日志消息内容.<br />
%p: 输出日志事件的priority（DEBUG、INFO等）.<br />
%r: 输出自程序启动后到当前的时间差，似乎用处不大。<br />
%c: 输出category名称，也就是getLogger函数的参数，用处也不大。<br />
%t: 输出当前的线程名，一些多线程环境中或许用的上。<br />
%x: 输出nested diagnostic context (NDC)，这个功能对多客户端请求的场景很有用。当使用日志查找分析问题时，很多时候希望针对某一个出问题的请求，查看它的执行流程，定位问题出在哪个环节，这就需要对一个请求的流程做唯一标识。这个唯一标识可以是全局唯一的logid，初始由最前端的模块分配，然后贯穿流程中的所有模块。也可以是其他东西，比如请求ip、请求参数等。这些信息可以通过log4j的NDC在日志中输出。NDC的结构如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> NDC <span style="color: #009900;">&#123;</span>
<span style="color: #666666; font-style: italic;">// Used when printing the diagnostic</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> get<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// Remove the top of the context from the NDC.</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> pop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// Add diagnostic context for the current thread.</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> push<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// Remove the diagnostic context for this thread.</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">void</span> remove<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>在处理请求的线程（比如servlet）中，新的请求开始处调用NDC.push方法设置标识，请求处理的最后再remove掉（也或者在push之前先remove）。</p>
<p>%n: 输出平台独立的换行符，如&#8221;\n&#8221;、&#8221;\r\n&#8221;等，通常和%m连用。<br />
WARNING：下面的参数有性能问题，对性能要求高的场景需要做好度量。<br />
%d: 输出时间，可以指定时间格式，比如 %d{HH:mm:ss,SSS} 或 %d{dd MMM yyyy HH:mm:ss,SSS}等。<br />
%C: 输出调用日志类方法者的fully-qualified类名，默认是输出全路径（也就是包名+类名），也可以限定{n}表示输出全称的最后n个部分，比如&#8221;com.foo.SomeClass&#8221;, 模式%C{1}将输出&#8221;SomeClass&#8221;。<br />
%M:输出调用日志类方法者的方法名。<br />
%F: 输出调用日志类方法者的文件名。<br />
%L: 输出调用日志类方法者的行号。<br />
%l: 输出调用日志类方法者的源代码位置，它是%C.%M(%F:%L)的简称。</p>
<p>上面的输出选项中，和调用者位置相关的选项会有性能问题。这是因为，为了得到这些信息，log4j调用 Throwable.getStackTrace()来得到整个调用过程的栈信息，自底向上比较调用的函数名，直到找到日志函数（debug等）的上一级函数名，然后通过反射得到一系列位置信息。这个过程显然要比其他几项的取得复杂的多，但它对分析日志查找问题却是很有用的。我的一个建议是，对于info 级别的日志，就不需要打出调用位置等信息，对于debug、warning和error则需要。另一个，输出时间也是很有必要的，否则做统计查问题都无从下手。</p>
<h2>5.Filter</h2>
<p>log4j中的filter可以指定appender要输出的日志等级范围，这可以实现在应用中把不同等级的日志打到不同文件中。像debug、info 级别，每天会产生很多，也多用来做统计分析；而warning和error级别的日志是需要监控处理的，并且人还有可能上去查看；所以把两者分开就显得很有必要。对于有特别需求的日志，也可以单独打到一个文件里去。下面是使用filter的一个样例：</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;appender</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;TRACE&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.ConsoleAppender&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.PatternLayout&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;ConversionPattern&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;[%t] %-5p %c - %m%n&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/layout<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.varia.LevelRangeFilter&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;levelMin&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;DEBUG&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;levelMax&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;INFO&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.varia.DenyAllFilter&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/appender<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>LevelRangeFilter可以指定某个范围（从levelMin到levelMax）的等级，在上面的配置中，如果没有 DenyAllFilter，表示从DEBUG到INFO级别的日志不做处理，而加了DenyAllFilter后含义反转，表示该appender只打印从DEBUG到INFO的日志。log4j中另一个实用的filter是LevelMatchFilter，它准确的匹配某个日志等级。</p>
<h2>6.Example</h2>
<p>下面是一个完整的log4j.xml配置文件样例：</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<span style="color: #00bbdd;">&lt;!DOCTYPE log4j:configuration SYSTEM &quot;log4j.dtd&quot;&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;log4j:configuration</span> <span style="color: #000066;">xmlns:log4j</span>=<span style="color: #ff0000;">&quot;http://jakarta.apache.org/log4j/&quot;</span></span>
<span style="color: #009900;"><span style="color: #000066;">debug</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;appender</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;info-out&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.DailyRollingFileAppender&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;File&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;${log_path}.log&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;DatePattern&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;'.'yyyy-MM-dd&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.PatternLayout&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;ConversionPattern&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;[%d{yyyy-MM-dd HH:mm:ss}][%p][%F(%L)]%m%n&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/layout<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.varia.LevelRangeFilter&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;LevelMin&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;debug&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;LevelMax&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;info&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;AcceptOnMatch&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.varia.DenyAllFilter&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/appender<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;appender</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;error-out&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.DailyRollingFileAppender&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;Append&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;DatePattern&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;'.'yyyy-MM-dd&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;File&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;${log_path}.wf.log&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.PatternLayout&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;ConversionPattern&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;[%d{yyyy-MM-dd HH:mm:ss}][%p][%F(%L)]%m%n&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/layout<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.varia.LevelRangeFilter&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;LevelMin&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;warn&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;LevelMax&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;error&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;AcceptOnMatch&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/filter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.apache.log4j.varia.DenyAllFilter&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/appender<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;root<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;level</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;debug&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;appender-ref</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;info-out&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;appender-ref</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;error-out&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/root<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;logger</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;com.danga&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;level</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;info&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/logger<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/log4j:configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>对于配置中的行</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;File&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;${log_path}.log&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>，log_path是java property（通过-D选项指定），log4j支持之。该配置达到的目标是：<br />
1）生成的日志文件有3个，一个是debug和info级别的日志，一个是warn和error级别的日志，还有一个是输出重定向的文件（主要是GC信息）。<br />
2）使用DailyRollingFileAppender切割日志文件。<br />
3）屏蔽了com.danga层级（memcached client库）的debug日志。</p>
<h2>7.Performance</h2>
<p>对于log4j的性能，我没有做细致的度量。抛开log4j来说，日志操作主要性能耗在输出上，所以输出的日志内容越少越好。除此之外，log4j使用上有两点需要注意：<br />
1、在生产环境中，我们通常是关掉debug级别的，但如果程序中debug函数很多，还是会带来性能问题。因为debug函数输出的就是些调试信息，所以其参数通常是多个字符串+操作构成，这种经典的构造多个临时对象的做法显然会有些性能消耗；更有甚者会调用诸如object.toString方法，而这个被覆盖的方法很可能是将对象内的诸多属性拼凑成字符串输出，对性能有高要求的场景就很不合适。在一些基础库或框架中，就可能会看到下面的代码片断来避免性能问题，其中的isDebugEnabled只是个判定操作，在logger层次不复杂的情况下，没有什么性能损失：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>logger.<span style="color: #006633;">isDebugEnabled</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
logger.<span style="color: #006633;">debug</span><span style="color: #009900;">&#40;</span>......<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>2、复杂的logger层级也会带来性能问题。好的方面是，通常我们指定root logger就够了。</p>
<h2>8.Conclusions</h2>
<p>关于java应用中的日志处理，暂且说到这里。尽管log4j很好很强大，但如果你的程序是些如库或框架等基础服务，可以考虑 slf4j（http://www.slf4j.org）来代替log4j的API调用。slf4j是对现存的多种日志库的封装，对外提供了统一的接口，解决了依赖的程序间的日志不兼容的问题。</p>
<h2>9.Reference</h2>
<p>http://logging.apache.org/log4j/1.2/manual.html</p>
<p>http://wiki.apache.org/logging-log4j/Log4jXmlFormat</p>
<p>http://www.vipan.com/htdocs/log4jhelp.html</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/05/147.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>google collections介绍</title>
		<link>http://www.kafka0102.com/2010/05/139.html</link>
		<comments>http://www.kafka0102.com/2010/05/139.html#comments</comments>
		<pubDate>Sat, 15 May 2010 06:25:46 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[BiMap]]></category>
		<category><![CDATA[google collections]]></category>
		<category><![CDATA[Immutable Collections]]></category>
		<category><![CDATA[MapMaker]]></category>
		<category><![CDATA[Multimap]]></category>
		<category><![CDATA[Multiset]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=139</guid>
		<description><![CDATA[google collections是google的工程师利用传说中的“20%时间”开发的集合库，它是对java.util的扩展，提供了很多实用的类来简化代码。google collections使用了范型，所以要求jdk1.5以上。它的作者没有像apache commons collections一样照顾老的jdk版本，一个原因是google的jdk基本都是1.5以上，另一个原因是类型转换实在是太难看了。现在的集合库版本是1.0,已经很稳定了，在功能和实现方面也是广泛参考意见（比如java.util之父Josh Bloch），所以该库的质量可想而知，将来也有可能集成到jdk中。项目地址是http://code.google.com/p/google-collections/，该文对其提供的核心类做简要的介绍。]]></description>
			<content:encoded><![CDATA[<p>google collections是google的工程师利用传说中的“20%时间”开发的集合库，它是对java.util的扩展，提供了很多实用的类来简化代码。google collections使用了范型，所以要求jdk1.5以上。它的作者没有像apache commons collections一样照顾老的jdk版本，一个原因是google的jdk基本都是1.5以上，另一个原因是类型转换实在是太难看了。现在的集合库版本是1.0,已经很稳定了，在功能和实现方面也是广泛参考意见（比如java.util之父Josh Bloch），所以该库的质量可想而知，将来也有可能集成到jdk中。项目地址是http://code.google.com/p/google-collections/，该文对其提供的核心类做简要的介绍。</p>
<h2>Immutable Collections</h2>
<p>在《effective java》的13条提到immutable class的好处及做法，有兴趣的可以参考该节。在immutable collections方面，java.util.Collections类提供了一系列unmodifiableFoo的静态方法供使用，这些unmodifiableFoo实际上是原有集合的视图包装，所以可以认为新生成的不变集合和原有集合是同一对象，只是不变集合不能调用修改操作。这种效果有时并不是真正想要的，有时需要的是生成的不变集合和原有集合是分离的，原有集合的后续操作不影响不变集合。google collections就提供了该功能，具体的就包括ImmutableList、ImmutableMap、ImmutableSet等。下面给出一个示例片断：</p>
<p>原有使用java.util.Collections的方法示例：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">&nbsp;
	List<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;</span> list <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ArrayList<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	list.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	list.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;2&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	list.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;3&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	List<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;</span> immutableList <span style="color: #339933;">=</span> <span style="color: #003399;">Collections</span>.<span style="color: #006633;">unmodifiableList</span><span style="color: #009900;">&#40;</span>list<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>使用com.google.common.collect.ImmutableList示例：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">&nbsp;
	List<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;</span> immutableList <span style="color: #339933;">=</span> ImmutableList.<span style="color: #006633;">of</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;1&quot;</span>,<span style="color: #0000ff;">&quot;2&quot;</span>,<span style="color: #0000ff;">&quot;3&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>com.google.common.collect.ImmutableFoo都是通过调用静态的of方法生成新的不变集合，该方法的参数是个可变数组。因为ImmutableFoo只提供读操作并自己维护数据，所以性能方面会比java.util中集合类有所提高。另外要说的是，不变集合并不能左右其包含的元素是否可变，所以不变集合中的元素最好也是不变的。</p>
<h2>Multiset &amp; Multimap</h2>
<p>java.util.Set是个无序且元素不重复的集合。而Multiset是个无序但添加元素可重复的集合，对添加的重复元素，以计数表示多少。Multiset的实现也是支持多种类型的（比如Hash、LinkedList等）下面是使用片断：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">&nbsp;
	Multiset<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;</span> set <span style="color: #339933;">=</span> HashMultiset.<span style="color: #006633;">create</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	set.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;kafka0102&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	set.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;kafka0102&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>set.<span style="color: #006633;">count</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;kafka0102&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//输出2</span>
&nbsp;
	set.<span style="color: #006633;">setCount</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;kafka0102&quot;</span>, <span style="color: #cc66cc;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>set.<span style="color: #006633;">count</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;kafka0102&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//输出5</span></pre></div></div>

<p>这个Multiset还是有很多应用场景的，比如统计用户访问计数，没有Multiset，就需要使用如Map来做，每次累加都需要先取出原有的计数值再加一后放回去，自然不如Multiset使用的方便。</p>
<p>Multimap也是很方便实用的集合，对于形如Multimap&lt;K,V&gt;的map，它相当于Map&lt;K,Collection&lt;V&gt;&gt;。如果实用Map来实现Multimap的功能，可想又是对Map的value进行三部曲操作。Multimap的实现也是支持多种类型的（比如Hash、LinkedList等）。使用Multimap的示例代码如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">&nbsp;
	Multimap<span style="color: #339933;">&lt;</span>String,String<span style="color: #339933;">&gt;</span> map <span style="color: #339933;">=</span> HashMultimap.<span style="color: #006633;">create</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;kafka0102&quot;</span>,<span style="color: #0000ff;">&quot;1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;kafka0102&quot;</span>,<span style="color: #0000ff;">&quot;2&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;kafka0102&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//输出[2, 1]</span></pre></div></div>

<h2>BiMap</h2>
<p>BiMap（bidirectional map）是个双向的map。java.util.Map是个正向Map，也就是根据key查value，如果需要根据value查key，或者需要反向得到Map&lt;V,K&gt;，BiMap就是很好的选择，否则就需要两个Map来做。它的具体实现类有：EnumBiMap, EnumHashBiMap, HashBiMap, ImmutableBiMap。示例代码如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">&nbsp;
	BiMap<span style="color: #339933;">&lt;</span>String,String<span style="color: #339933;">&gt;</span> map <span style="color: #339933;">=</span> HashBiMap.<span style="color: #006633;">create</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;kafka0102&quot;</span>,<span style="color: #0000ff;">&quot;1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;kafka0102&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">inverse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//输出反向数据没有提供单独的函数，而是需要调用inverse().get</span></pre></div></div>

<h2>MapMaker</h2>
<p>MapMaker是对ConcurrentMap的builder，它使得ConcurrentMap的key和value能是弱引用或软引用类型。特别的，它提供的makeComputingMap方法能根据key计算出value来，当没有对key来put value时，生成的ConcurrentMap能根据Function计算出value并和key关联上，后续的访问就不需要再次计算。代码示例如下：</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">&nbsp;
	ConcurrentMap<span style="color: #339933;">&lt;</span>String, Integer<span style="color: #339933;">&gt;</span> map <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> MapMaker<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
		.<span style="color: #006633;">concurrencyLevel</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">32</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">softKeys</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">weakValues</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">expiration</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">30</span>,
			TimeUnit.<span style="color: #006633;">MINUTES</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">makeComputingMap</span><span style="color: #009900;">&#40;</span>
&nbsp;
		<span style="color: #000000; font-weight: bold;">new</span> Function<span style="color: #339933;">&lt;</span>String, Integer<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
			<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Integer</span> apply<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
				<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #003399;">Integer</span>.<span style="color: #006633;">parseInt</span><span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;123&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//输出123</span>
&nbsp;
	map.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;123&quot;</span>, <span style="color: #cc66cc;">124</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;123&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//输出124</span></pre></div></div>

<p>google collections还提供一些实用的类，具体可参考它的API doc和http://publicobject.com/2007/09/series-recap-coding-in-small-with.html。该文虽行止于此，也很建议大家有时间研究下google collections的实现，这种基础库看起来简单但要实现的优雅、高效是需要很见功夫的。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/05/139.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jvm关闭钩子与信号处理</title>
		<link>http://www.kafka0102.com/2010/04/107.html</link>
		<comments>http://www.kafka0102.com/2010/04/107.html#comments</comments>
		<pubDate>Sat, 01 May 2010 07:51:34 +0000</pubDate>
		<dc:creator>kafka0102</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[addShutdownHook]]></category>
		<category><![CDATA[jvm]]></category>
		<category><![CDATA[shutdown hooks]]></category>
		<category><![CDATA[信号处理]]></category>

		<guid isPermaLink="false">http://www.kafka0102.com/?p=107</guid>
		<description><![CDATA[对于使用Java做server端程序来说，通常会希望在JVM关闭时做些扫尾工作，比如写内存数据到磁盘、关闭句柄等。JVM提供了关闭钩子（shutdown hooks）来做这件事情。关闭钩子使用起来很简单，调用Runtime实例的public void addShutdownHook(Thread hook)即可，其中参数hook就是要做扫尾工作的钩子线程。这就是说，调用这个方法，JVM便会在初始化时注册这个钩子，待时机到了触发钩子。而触发的时机有：1）程序正常推出或者调用System.exit方法，如果是多线程环境，要求是最后一个非守护线程触发，2）JVM收到需要关闭自己的信号（比如SIGINT、SIGTERM等，但像SIGKILL，JVM就没有机会去处理了），也或者发生如系统关闭这种不可阻挡的事件。]]></description>
			<content:encoded><![CDATA[<p>对于使用Java做server端程序来说，通常会希望在JVM关闭时做些扫尾工作，比如写内存数据到磁盘、关闭句柄等。JVM提供了关闭钩子（shutdown hooks）来做这件事情。关闭钩子使用起来很简单，调用Runtime实例的public void addShutdownHook(Thread hook)即可，其中参数hook就是要做扫尾工作的钩子线程。这就是说，调用这个方法，JVM便会在初始化时注册这个钩子，待时机到了触发钩子。而触发的时机有：1）程序正常退出或者调用System.exit方法，如果是多线程环境，要求是最后一个非守护线程终止，2）JVM收到需要关闭自己的信号（比如SIGINT、SIGTERM等，但像SIGKILL，JVM就没有机会去处理了），也或者发生如系统关闭这种不可阻挡的事件。<br />
<br />
对于addShutdownHook中的钩子代码，也是有一些要注意的地方，下面列举几点：<br />
1、关闭钩子可以注册多个，在关闭JVM时就会起多个线程来运行钩子。通常来说，一个钩子就足够了，但如果需要启用多个钩子，就需要注意并发带来的问题。<br />
2、钩子里也要注意对异常的处理，如果不幸抛出了异常，那么钩子的执行序列就会被终止。<br />
3、在钩子运行期间，工作线程也在运行，需要考虑到工作线程是否会对钩子的执行带来影响，我最近发现的一个bug就是这种情况，场景是钩子要关闭文件句柄，但因为同时server还接收提交请求，结果文件又被打开，造成不想要的结果。<br />
4、钩子里的代码尽可能简洁，否则当像系统关闭等情景可能钩子来不及运行完JVM就被退出了。</p>
<p>话题转到信号处理上，我们知道在linux下c服务端编程里，信号处理是必不可少的，它除了像JVM那样可以在程序退出前做些扫尾工作，还可以针对特定的信号做些实用的处理，比如自定义信号来重新加载文件等（当然这个功能使用一个线程轮询检查也是很方便的）。但不管怎么说，在Linux c中，你是可控信号的。但在Java，JVM掌管着信号处理，这使得程序端无法对信号做处理。这也可以理解，就像一些Server它本身对各种信号做了处理，如果你写个挂在它下面的扩展也对信号做处理，就可能出现冲突。不过，如果你真想在Java里做信号处理，也是有办法的，jdk里提供了相关可使用的接口，那就是sun.misc包下的Signal和SignalHandler。不过看名字就知道这个东西不靠谱，人家也强烈不建议你用。我测试的结果时，在eclipse里根本不能自动编译通过，使用javac编译会给出警告信息”sun.misc.Signal 是 Sun 的专用 API，可能会在未来版本中删除“。所以，就不要想在Java里做信号处理了，还是想想其他方法来解决问题吧。</p>
<p>附，关于JVM的关闭钩子及信号处理，<a title="Revelations on Java signal handling and termination" href="http://www.ibm.com/developerworks/java/library/i-signalhandling/" target="_blank">http://www.ibm.com/developerworks/java/library/i-signalhandling/</a> 很值得一读。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kafka0102.com/2010/04/107.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

