﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-黑灵客栈</title><link>http://www.blogjava.net/mstar/</link><description>黑灵的没啥技术含量的技术博客! -&gt; http://zjumty.iteye.com</description><language>zh-cn</language><lastBuildDate>Sun, 19 Apr 2026 14:51:24 GMT</lastBuildDate><pubDate>Sun, 19 Apr 2026 14:51:24 GMT</pubDate><ttl>60</ttl><item><title>在传输层上压缩WebService的请求和响应 </title><link>http://www.blogjava.net/mstar/archive/2013/06/23/400884.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Sun, 23 Jun 2013 13:45:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2013/06/23/400884.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/400884.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2013/06/23/400884.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/400884.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/400884.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 场景				场景是这样的：客户端.NET 3.5应用程序，WCF实现WebService调用， 服务端Java，通过CXF提供WebService。 有一个方法提供了有一个字符串类型的参数，实际生产环境里会传100k以上的字符串。在并发量比较大的情况下，带宽占用很严重。所以寻找一种可以把传输的SOAP消息在客户端压缩，服务端解压缩的方法。这里提供的方式在是客户端通过WCF的...&nbsp;&nbsp;<a href='http://www.blogjava.net/mstar/archive/2013/06/23/400884.html'>阅读全文</a><img src ="http://www.blogjava.net/mstar/aggbug/400884.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2013-06-23 21:45 <a href="http://www.blogjava.net/mstar/archive/2013/06/23/400884.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在MongoDB里实现循环序列功能 </title><link>http://www.blogjava.net/mstar/archive/2013/04/26/398469.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Fri, 26 Apr 2013 14:57:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2013/04/26/398469.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/398469.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2013/04/26/398469.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/398469.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/398469.html</trackback:ping><description><![CDATA[<div id="blog_content" class="blog_content">
    <div style="font-size: 14px;" class="iteye-blog-content-contain">
<p>环境是这样的：服务器是用Java做的， 数据库是MongoDB</p>
<p>&nbsp;</p>
<p>需求是这样的：我们的系统里要生成一个唯一ID，前面的部分有一定的格式，并和时间关联， 精确到微秒，考虑到同一微秒内有可能存在并发情况， 
所以后面在加两位序列号， 系统需要定义为1毫秒内的并发小于100个，所以后面两位就够用了。 
Java服务器端有多台机器都可以用来生成这个唯一ID，所以需要在不同的机器上不能生成相同的序列号，所以需要在某一点上做全局的范围同步来保存这序列
号的唯一性。 其实如果不考虑需求里的唯一ID是有一定意义的格式的， 
用UUID或MongoDB的ObjectId都是更好的选择，完全不需要在某一点上进行同步，性能会更好。</p>
<p>&nbsp;</p>
<p>这个可以生成序列号的点， 我们可以做一个序列号生成服务器来对应， 也可以用数据库来对应。 
单单为这个简单的功能准备一个服务器来做显然不合适。 但是我们用的MongoDB并没有类似于MySQL或Oracle中的SELECT FOR 
UPDATE这样的锁机制。 所以没有办法简单的对这个序列号做原子操作。 
但是MongoDB的对单个document进行update操作中有很是具有原子性的， 例如</p>
<ul><li>$set</li><li>$unset</li><li>$inc</li><li>$push</li><li>$pushAll</li><li>$pull</li><li>$pullAll</li></ul>
<p>我们可以利用这些原子操作，在数据库层以乐观锁的形式来实现循环序列字段。为了方便调用我把这段逻辑做成数据库中的Javascript函数。 类似与MySQL中的存储过程。</p>
<p>&nbsp;</p>
<p>首先我们需要一个collection来存放序列号，并对需要的需要的序列号进行初始化。我们叫它counters。</p>
<div id="" class="dp-highlighter"><div class="bar"><div class="tools">Js代码 &nbsp;<a title="收藏这段代码"><img class="star" src="http://zjumty.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol class="dp-c" start="1"><li><span><span>db.counters.save({_id:</span><span class="string">"SerialNo1"</span><span>,&nbsp;val:0,&nbsp;maxval:99})&nbsp;&nbsp;</span></span></li></ol></div>
<p>&nbsp;</p>
<p>然后我们想system.js里添加一个Javascript函数</p>
<div id="" class="dp-highlighter"><div class="bar"><div class="tools">Js代码 &nbsp;<a title="收藏这段代码"><img class="star" src="http://zjumty.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol class="dp-c" start="1"><li><span><span>db.system.js.save({_id:</span><span class="string">"getNextUniqueSeq"</span><span>,&nbsp;&nbsp;</span></span></li><li><span>value:<span class="keyword">function</span><span>&nbsp;(keyName)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">var</span><span>&nbsp;seqObj&nbsp;=&nbsp;db.counters.findOne({_id:keyName});&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(seqObj&nbsp;==&nbsp;</span><span class="keyword">null</span><span>)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(<span class="string">"can&nbsp;not&nbsp;find&nbsp;record&nbsp;with&nbsp;key:&nbsp;"</span><span>&nbsp;+&nbsp;keyName);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;-1;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;the&nbsp;max&nbsp;value&nbsp;of&nbsp;sequence</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">var</span><span>&nbsp;maxVal&nbsp;=&nbsp;seqObj.maxval;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;the&nbsp;current&nbsp;value&nbsp;of&nbsp;sequence</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">var</span><span>&nbsp;curVal&nbsp;=&nbsp;seqObj.val;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">while</span><span>(</span><span class="keyword">true</span><span>){&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;if&nbsp;curVal&nbsp;reach&nbsp;max,&nbsp;reset&nbsp;it</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(curVal&nbsp;&gt;=&nbsp;maxVal){&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.counters.update({_id&nbsp;:&nbsp;keyName,&nbsp;val&nbsp;:&nbsp;curVal},&nbsp;{&nbsp;$set&nbsp;:&nbsp;{&nbsp;val&nbsp;:&nbsp;0&nbsp;}},&nbsp;<span class="keyword">false</span><span>,&nbsp;</span><span class="keyword">false</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">var</span><span>&nbsp;err&nbsp;=&nbsp;db.getLastErrorObj();&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(&nbsp;err&nbsp;&amp;&amp;&nbsp;err.code&nbsp;)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(&nbsp;<span class="string">"unexpected&nbsp;error&nbsp;reset&nbsp;data:&nbsp;"</span><span>&nbsp;+&nbsp;tojson(&nbsp;err&nbsp;)&nbsp;);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;-2;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;</span><span class="keyword">if</span><span>&nbsp;(err.n&nbsp;==&nbsp;0){&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;fail&nbsp;to&nbsp;reset&nbsp;value,&nbsp;may&nbsp;be&nbsp;reseted&nbsp;by&nbsp;others</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(<span class="string">"fail&nbsp;to&nbsp;reset&nbsp;value:&nbsp;"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;get&nbsp;current&nbsp;value&nbsp;again.</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;seqObj&nbsp;=&nbsp;db.counters.findOne({_id:keyName});&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxVal&nbsp;=&nbsp;seqObj.maxval;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curVal&nbsp;=&nbsp;seqObj.val;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">continue</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;if&nbsp;curVal&nbsp;not&nbsp;reach&nbsp;the&nbsp;max,&nbsp;inc&nbsp;it;</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;increase&nbsp;</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.counters.update({_id&nbsp;:&nbsp;keyName,&nbsp;val&nbsp;:&nbsp;curVal},&nbsp;{&nbsp;$inc&nbsp;:&nbsp;{&nbsp;val&nbsp;:&nbsp;1&nbsp;}},&nbsp;<span class="keyword">false</span><span>,&nbsp;</span><span class="keyword">false</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">var</span><span>&nbsp;err&nbsp;=&nbsp;db.getLastErrorObj();&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>(&nbsp;err&nbsp;&amp;&amp;&nbsp;err.code&nbsp;)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(&nbsp;<span class="string">"unexpected&nbsp;error&nbsp;inc&nbsp;val:&nbsp;"</span><span>&nbsp;+&nbsp;tojson(&nbsp;err&nbsp;)&nbsp;);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;-3;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;</span><span class="keyword">if</span><span>&nbsp;(err.n&nbsp;==&nbsp;0){&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;fail&nbsp;to&nbsp;reset&nbsp;value,&nbsp;may&nbsp;be&nbsp;increased&nbsp;by&nbsp;others</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(<span class="string">"fail&nbsp;to&nbsp;inc&nbsp;value:&nbsp;"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;get&nbsp;current&nbsp;value&nbsp;again.</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;seqObj&nbsp;=&nbsp;db.counters.findOne({_id:keyName});&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxVal&nbsp;=&nbsp;seqObj.maxval;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curVal&nbsp;=&nbsp;seqObj.val;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">continue</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">else</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">var</span><span>&nbsp;retVal&nbsp;=&nbsp;curVal&nbsp;+&nbsp;1;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(<span class="string">"success&nbsp;to&nbsp;get&nbsp;seq&nbsp;:&nbsp;"</span><span>&nbsp;+&nbsp;retVal);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;increase&nbsp;successful</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;retVal;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li><li><span>});&nbsp;&nbsp;</span></li></ol></div>
<p>上面这段会把指定的序列号的val值+1，如果val达到上限则从0开始。所以叫循环序列。</p>
<p>&nbsp;</p>
<p>其实上面的实现在原理上和Java里的AtomicInteger系列的功能实现是类似的，利用循环重试和原子性的CAS来实现。这种实现方式在多线程的环境里由于锁（Monitor）的范围很小，所以并发性上比排他锁要好一些。</p>
<p>&nbsp;</p>
<p>下面我们用Java来测试一下这个函数的正确性。 即在多线程的情况下会不会得到重复的序列号。</p>
<p>&nbsp;</p>
<p>第一个测试，val=0， maxval=2000， Java端20个线程每个线程循环调用100次。 共2000次。 所以正确的情况下，从0到1999应该每个数字只出现一次。</p>
<p>&nbsp;</p>
<div id="" class="dp-highlighter"><div class="bar"><div class="tools">Java代码 &nbsp;<a title="收藏这段代码"><img class="star" src="http://zjumty.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol class="dp-j" start="1"><li><span><span class="annotation">@Test</span><span>&nbsp;&nbsp;</span></span></li><li><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;testGetNextUniqueSeq1()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">final</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;THREAD_COUNT&nbsp;=&nbsp;</span><span class="number">20</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">final</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;LOOP_COUNT&nbsp;=&nbsp;</span><span class="number">100</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;Mongo&nbsp;mongoClient&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Mongo(</span><span class="string">"172.17.2.100"</span><span>,&nbsp;</span><span class="number">27017</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;DB&nbsp;db&nbsp;=&nbsp;mongoClient.getDB(<span class="string">"im"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;db.authenticate(<span class="string">"imadmin"</span><span>,&nbsp;</span><span class="string">"imadmin"</span><span>.toCharArray());&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;BasicDBObject&nbsp;q&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;BasicDBObject();&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;q.put(<span class="string">"_id"</span><span>,&nbsp;</span><span class="string">"UNIQUE_KEY"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;BasicDBObject&nbsp;upd&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;BasicDBObject();&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;BasicDBObject&nbsp;set&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;BasicDBObject();&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;set.put(<span class="string">"val"</span><span>,&nbsp;</span><span class="number">0</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;set.put(<span class="string">"maxval"</span><span>,&nbsp;THREAD_COUNT&nbsp;*&nbsp;LOOP_COUNT);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;upd.put(<span class="string">"$set"</span><span>,&nbsp;set);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;db.getCollection(<span class="string">"counters"</span><span>).update(q,&nbsp;upd);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;Thread[]&nbsp;threads&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Thread[THREAD_COUNT];&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">final</span><span>&nbsp;</span><span class="keyword">int</span><span>[][]&nbsp;results&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;</span><span class="keyword">int</span><span>[THREAD_COUNT][LOOP_COUNT];&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;i&nbsp;&lt;&nbsp;THREAD_COUNT;&nbsp;i++)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">final</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;temp_i&nbsp;=&nbsp;i;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threads[i]&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Thread(</span><span class="string">""</span><span>&nbsp;+&nbsp;i)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="annotation">@Override</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;run()&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">try</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Mongo&nbsp;mongoClient&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Mongo(</span><span class="string">"172.17.2.100"</span><span>,&nbsp;</span><span class="number">27017</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DB&nbsp;db&nbsp;=&nbsp;mongoClient.getDB(<span class="string">"im"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.authenticate(<span class="string">"imadmin"</span><span>,&nbsp;</span><span class="string">"imadmin"</span><span>.toCharArray());&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;j&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;j&nbsp;&lt;&nbsp;LOOP_COUNT;&nbsp;j++)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;result&nbsp;=&nbsp;db.eval(<span class="string">"getNextUniqueSeq(\"UNIQUE_KEY\")"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.printf(<span class="string">"Thread&nbsp;%s,&nbsp;seq=%d\n"</span><span>,&nbsp;Thread.currentThread().getName(),&nbsp;((Double)&nbsp;result).intValue());&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;results[temp_i][j]&nbsp;=&nbsp;((Double)&nbsp;result).intValue();&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">catch</span><span>&nbsp;(UnknownHostException&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(Thread&nbsp;thread&nbsp;:&nbsp;threads)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thread.start();&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(Thread&nbsp;thread&nbsp;:&nbsp;threads)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thread.join();&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;num&nbsp;=&nbsp;</span><span class="number">1</span><span>;&nbsp;num&nbsp;&lt;=&nbsp;LOOP_COUNT&nbsp;*&nbsp;THREAD_COUNT;&nbsp;num++)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;every&nbsp;number&nbsp;appear&nbsp;1&nbsp;times&nbsp;only!</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;times&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;j&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;j&nbsp;&lt;&nbsp;THREAD_COUNT;&nbsp;j++)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;k&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;k&nbsp;&lt;&nbsp;LOOP_COUNT;&nbsp;k++)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(results[j][k]&nbsp;==&nbsp;num)&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;times++;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(<span class="number">1</span><span>,&nbsp;times);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div>
<p>&nbsp;</p>
<p>然后我们再测试一下循环的情况。 val=0, maxval=99。 同样是Java端20个线程每个线程循环调用100次。 共2000次。这次从0到99的数字每个应该取得20次。</p>
<p>&nbsp;</p>
<div id="" class="dp-highlighter"><div class="bar"><div class="tools">Java代码 &nbsp;<a title="收藏这段代码"><img class="star" src="http://zjumty.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol class="dp-j" start="1"><li><span><span class="annotation">@Test</span><span>&nbsp;&nbsp;</span></span></li><li><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;testGetNextUniqueSeq2()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">final</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;THREAD_COUNT&nbsp;=&nbsp;</span><span class="number">20</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">final</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;LOOP_COUNT&nbsp;=&nbsp;</span><span class="number">100</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;Mongo&nbsp;mongoClient&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Mongo(</span><span class="string">"172.17.2.100"</span><span>,&nbsp;</span><span class="number">27017</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;DB&nbsp;db&nbsp;=&nbsp;mongoClient.getDB(<span class="string">"im"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;db.authenticate(<span class="string">"imadmin"</span><span>,&nbsp;</span><span class="string">"imadmin"</span><span>.toCharArray());&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;BasicDBObject&nbsp;q&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;BasicDBObject();&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;q.put(<span class="string">"_id"</span><span>,&nbsp;</span><span class="string">"UNIQUE_KEY"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;BasicDBObject&nbsp;upd&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;BasicDBObject();&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;BasicDBObject&nbsp;set&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;BasicDBObject();&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;set.put(<span class="string">"val"</span><span>,&nbsp;</span><span class="number">0</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;set.put(<span class="string">"maxval"</span><span>,&nbsp;LOOP_COUNT);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;upd.put(<span class="string">"$set"</span><span>,&nbsp;set);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;db.getCollection(<span class="string">"counters"</span><span>).update(q,&nbsp;upd);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;Thread[]&nbsp;threads&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Thread[THREAD_COUNT];&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">final</span><span>&nbsp;</span><span class="keyword">int</span><span>[][]&nbsp;results&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;</span><span class="keyword">int</span><span>[THREAD_COUNT][LOOP_COUNT];&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;i&nbsp;&lt;&nbsp;THREAD_COUNT;&nbsp;i++)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">final</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;temp_i&nbsp;=&nbsp;i;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threads[i]&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Thread(</span><span class="string">""</span><span>&nbsp;+&nbsp;i)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="annotation">@Override</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;run()&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">try</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Mongo&nbsp;mongoClient&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Mongo(</span><span class="string">"172.17.2.100"</span><span>,&nbsp;</span><span class="number">27017</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DB&nbsp;db&nbsp;=&nbsp;mongoClient.getDB(<span class="string">"im"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.authenticate(<span class="string">"imadmin"</span><span>,&nbsp;</span><span class="string">"imadmin"</span><span>.toCharArray());&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;j&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;j&nbsp;&lt;&nbsp;LOOP_COUNT;&nbsp;j++)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;result&nbsp;=&nbsp;db.eval(<span class="string">"getNextUniqueSeq(\"UNIQUE_KEY\")"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.printf(<span class="string">"Thread&nbsp;%s,&nbsp;seq=%d\n"</span><span>,&nbsp;Thread.currentThread().getName(),&nbsp;((Double)&nbsp;result).intValue());&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;results[temp_i][j]&nbsp;=&nbsp;((Double)&nbsp;result).intValue();&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">catch</span><span>&nbsp;(UnknownHostException&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(Thread&nbsp;thread&nbsp;:&nbsp;threads)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thread.start();&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(Thread&nbsp;thread&nbsp;:&nbsp;threads)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thread.join();&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;num&nbsp;=&nbsp;</span><span class="number">1</span><span>;&nbsp;num&nbsp;&lt;=&nbsp;LOOP_COUNT;&nbsp;num++)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;every&nbsp;number&nbsp;appear&nbsp;20&nbsp;times&nbsp;only!</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;times&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;j&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;j&nbsp;&lt;&nbsp;THREAD_COUNT;&nbsp;j++)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">int</span><span>&nbsp;k&nbsp;=&nbsp;</span><span class="number">0</span><span>;&nbsp;k&nbsp;&lt;&nbsp;LOOP_COUNT;&nbsp;k++)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(results[j][k]&nbsp;==&nbsp;num)&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;times++;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(<span class="number">20</span><span>,&nbsp;times);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div>
<p>&nbsp;</p>
<p>这个测试跑了几次都是正确的。</p>
<p>&nbsp;</p>
<p>由于没有可以进行对比其他的实现方式（例如排他锁）所以没有做性能测试。</p>
<p>&nbsp;</p>
<p>写在最后。 虽然MongoDB支持类似于存储过程的Stored 
Javascript，但是其实不建议使用这个来解决复杂问题。主要原因是没法调试，维护起来太不方便。而且在2.4之前MongoDB对服务端
Javascript支持并不是很好， 
一个mongod进程同时只能执行一段Javascript。如果能在应用层解决掉还是在应用层里实现逻辑比较好。</p>
</div>
  </div><img src ="http://www.blogjava.net/mstar/aggbug/398469.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2013-04-26 22:57 <a href="http://www.blogjava.net/mstar/archive/2013/04/26/398469.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>输出debug信息到postfix的log</title><link>http://www.blogjava.net/mstar/archive/2013/04/26/398459.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Fri, 26 Apr 2013 11:25:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2013/04/26/398459.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/398459.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2013/04/26/398459.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/398459.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/398459.html</trackback:ping><description><![CDATA[可以通过以下设置把postfix的debug级别的log打印出来.<br /><br /><div>/etc/postfix/main.cf</div><br /><div>debug_peer_list = example.com<br /> debug_peer_level = 2</div><br /><div>/etc/postfix/master.cf</div><div>smtp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inet&nbsp; n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; smtpd -v</div><img src ="http://www.blogjava.net/mstar/aggbug/398459.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2013-04-26 19:25 <a href="http://www.blogjava.net/mstar/archive/2013/04/26/398459.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java里的CompareAndSet(CAS)</title><link>http://www.blogjava.net/mstar/archive/2013/04/24/398351.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Wed, 24 Apr 2013 09:20:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2013/04/24/398351.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/398351.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2013/04/24/398351.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/398351.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/398351.html</trackback:ping><description><![CDATA[
		<span style="color: #000000; ">
				<span style="color: #000000; ">
						<span style="color: #000000; ">Atomic</span>
				</span>
		</span>从JDK5开始, java.util.concurrent包里提供了很多面向并发编程的类. 使用这些类在多核CPU的机器上会有比较好的性能.<br />主要原因是这些类里面大多使用(失败-重试方式的)乐观锁而不是synchronized方式的悲观锁.<br /><br />今天有时间跟踪了一下AtomicInteger的incrementAndGet的实现.<br />本人对并发编程也不是特别了解, 在这里就是做个笔记, 方便以后再深入研究.<br /><br />1. incrementAndGet的实现<br /><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">final</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> incrementAndGet() {<br />        </span><span style="color: #0000FF; ">for</span><span style="color: #000000; "> (;;) {<br />            </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> current </span><span style="color: #000000; ">=</span><span style="color: #000000; "> get();<br />            </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> next </span><span style="color: #000000; ">=</span><span style="color: #000000; "> current </span><span style="color: #000000; ">+</span><span style="color: #000000; "> </span><span style="color: #000000; ">1</span><span style="color: #000000; ">;<br />            </span><span style="color: #0000FF; ">if</span><span style="color: #000000; "> (compareAndSet(current, next))<br />                </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> next;<br />        }<br />    }</span></div><br />首先可以看到他是通过一个无限循环(spin)直到increment成功为止.  <br />循环的内容是<br />1.取得当前值<br />2.计算+1后的值<br />3.如果当前值还有效(没有被)的话设置那个+1后的值<br />4.如果设置没成功(当前值已经无效了即被别的线程改过了), 再从1开始.<br /><br />2. <span style="color: #000000; ">compareAndSet的实现<br /><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">final</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; "> compareAndSet(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> expect, </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> update) {<br />        </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> unsafe.compareAndSwapInt(</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">, valueOffset, expect, update);<br />    }</span></div><br />直接调用的是UnSafe这个类的</span><span style="color: #000000; "><span style="color: #000000; ">compareAndSwapInt方法<br />全称是</span></span><span class="entity-name" title="sun.misc.Unsafe">sun.misc.Unsafe. 这个类是Oracle(Sun)提供的实现. 可以在别的公司的JDK里就不是这个类了<br /><br />3. </span><span style="color: #000000; "><span style="color: #000000; ">compareAndSwapInt的实现<br /><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">    </span><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />     * Atomically update Java variable to &lt;tt&gt;x&lt;/tt&gt; if it is currently<br />     * holding &lt;tt&gt;expected&lt;/tt&gt;.<br />     * </span><span style="color: #808080; ">@return</span><span style="color: #008000; "> &lt;tt&gt;true&lt;/tt&gt; if successful<br />     </span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">final</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">native</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">boolean</span><span style="color: #000000; "> compareAndSwapInt(Object o, </span><span style="color: #0000FF; ">long</span><span style="color: #000000; "> offset,<br />                                                  </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> expected,<br />                                                  </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> x);</span></div><br />可以看到, 不是用Java实现的, 而是通过JNI调用操作系统的原生程序.<br /><br />4. </span></span><span class="entity-name" title="sun.misc.Unsafe"></span><span style="color: #000000; "><span style="color: #000000; ">compareAndSwapInt的native实现</span></span><span style="color: #000000; "><span style="color: #000000; "><br />如果你下载了OpenJDK的源代码的话在hotspot\src\share\vm\prims\目录下可以找到unsafe.cpp<br /><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv </span><span style="color: #000000; ">*</span><span style="color: #000000; ">env, jobject </span><span style="color: #0000FF; ">unsafe</span><span style="color: #000000; ">, jobject obj, jlong offset, jint e, jint x))<br />  UnsafeWrapper(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Unsafe_CompareAndSwapInt</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />  oop p </span><span style="color: #000000; ">=</span><span style="color: #000000; "> JNIHandles::resolve(obj);<br />  jint</span><span style="color: #000000; ">*</span><span style="color: #000000; "> addr </span><span style="color: #000000; ">=</span><span style="color: #000000; "> (jint </span><span style="color: #000000; ">*</span><span style="color: #000000; ">) index_oop_from_field_offset_long(p, offset);<br />  </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> (jint)(Atomic::cmpxchg(x, addr, e)) </span><span style="color: #000000; ">==</span><span style="color: #000000; "> e;<br />UNSAFE_END</span></div><br />可以看到实际上调用</span></span><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; ">Atomic类的</span></span></span><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; ">cmpxchg方法.<br /><br />5. </span></span></span><span style="color: #000000; "><span style="color: #000000; "></span></span><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; ">Atomic的</span></span></span><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "></span></span></span><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; ">cmpxchg<br />这个类的实现是跟操作系统有关, 跟CPU架构也有关, 如果是windows下x86的架构<br />实现在hotspot\src\os_cpu\windows_x86\vm\目录的atomic_windows_x86.inline.hpp文件里<br /><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">inline jint     Atomic::cmpxchg    (jint     exchange_value, </span><span style="color: #0000FF; ">volatile</span><span style="color: #000000; "> jint</span><span style="color: #000000; ">*</span><span style="color: #000000; ">     dest, jint     compare_value) {<br />  </span><span style="color: #008000; ">//</span><span style="color: #008000; "> alternative for InterlockedCompareExchange</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">  </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> mp </span><span style="color: #000000; ">=</span><span style="color: #000000; "> os::is_MP();<br />  __asm {<br />    mov edx, dest<br />    mov ecx, exchange_value<br />    mov eax, compare_value<br />    LOCK_IF_MP(mp)<br />    cmpxchg dword ptr [edx], ecx<br />  }<br />}</span></div><br />在这里可以看到是用嵌入的汇编实现的, 关键CPU指令是</span></span></span><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "> cmpxchg<br />到这里没法再往下找代码了. 也就是说CAS的原子性实际上是CPU实现的. 其实在这一点上还是有排他锁的. 只是比起用synchronized, 这里的排他时间要短的多. 所以在多线程情况下性能会比较好.<br /><br />代码里有个</span></span></span></span></span></span></span><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #008000; "><font color="#000000">alternative for InterlockedCompareExchange<br />这个</font></span></span></span></span></span></span></span></span></span></span></span><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #008000; "><font color="#000000"><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #008000; "><font color="#000000">InterlockedCompareExchange是WINAPI里的一个函数, 做的事情和上面这段汇编是一样的<br />http://msdn.microsoft.com/en-us/library/windows/desktop/ms683560%28v=vs.85%29.aspx<br /></font></span></span></span></span></span></span></span></span></span></span></span></font></span><span style="color: #008000; "></span></span></span></span><br />6. 最后再贴一下x86的cmpxchg指定<br /></span></span></span></span></span></span></span><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><span style="color: #000000; "><font face="Lucida Console, Courier New"><h3>Opcode CMPXCHG</h3><br />CPU: I486+
 <br />Type of Instruction: User
 <br /><br />Instruction: CMPXCHG dest, src
 <br /><br />Description: Compares the accumulator with dest. If equal the "dest"
 <br />is loaded with "src", otherwise the accumulator is loaded
 <br />with "dest".
 <br /><br />Flags Affected:	AF, CF, OF, PF, SF, ZF
 <br /><br />CPU mode: RM,PM,VM,SMM
 <br />+++++++++++++++++++++++
 <br />Clocks:
 <br />CMPXCHG reg, reg	6
 <br />CMPXCHG mem, reg	7 (10 if compartion fails)
 <br /><br /><br /></font> </span></span></span></span></span></span></span><img src ="http://www.blogjava.net/mstar/aggbug/398351.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2013-04-24 17:20 <a href="http://www.blogjava.net/mstar/archive/2013/04/24/398351.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Apache Mina 中文文档翻译 - 特性</title><link>http://www.blogjava.net/mstar/archive/2013/04/23/398309.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Tue, 23 Apr 2013 14:02:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2013/04/23/398309.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/398309.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2013/04/23/398309.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/398309.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/398309.html</trackback:ping><description><![CDATA[特性<br />http://mina.apache.org/mina-project/features.html<br /><br />MINA是一个简单的却有功能丰富的网络应用程序框架， 它提供如下特性：<br /><ul><li>为各种传输类型提供一套统一的API</li></ul><blockquote><ul><li>通过Java NIO实现 TCP/IP &amp; UPD/IP通信</li></ul></blockquote><blockquote><ul><li>通过RXTX实现串口通信（RS232）</li></ul></blockquote><blockquote><ul><li>VM内部管道通信</li></ul></blockquote><blockquote><ul><li>你可以实现自己的通信方式</li></ul></blockquote><ul><li>通过Filter接口实现扩展点；类似与Servlet的Filter</li></ul><ul><li>低级和高级的API</li></ul><blockquote><ul><li>低级：使用ByteBuffer</li></ul></blockquote><blockquote><ul><li>高级：用户自定义的消息对象和编码</li></ul></blockquote><ul><li>可以自由定制的线程模型</li></ul><blockquote><ul><li>单线程</li></ul></blockquote><blockquote><ul><li>一个线程池</li></ul></blockquote><blockquote><ul><li>多个线程池（例如 <a target="_blank" title="SEDA" href="http://www.eecs.harvard.edu/~mdw/proj/seda/">SEDA</a>）</li></ul></blockquote><ul><li>利用Java5的SSLEngine实现的开箱即用的SSL,TLS, StartTLS功能</li></ul><ul><li>过载保护 和 带宽限制</li></ul><ul><li>通过Mock对象可以进行单体测试</li></ul><ul><li>通过JMX管理服务器</li></ul><ul><li>通过StreamIoHandler支持基于流的I/O</li></ul><ul><li>可以整合进PicoContainer和Spring等常用容器</li></ul><ul><li>很容易从Netty迁移过来。</li></ul><br /><img src ="http://www.blogjava.net/mstar/aggbug/398309.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2013-04-23 22:02 <a href="http://www.blogjava.net/mstar/archive/2013/04/23/398309.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Apache Mina 中文文档翻译 - 概述</title><link>http://www.blogjava.net/mstar/archive/2013/04/22/398241.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Mon, 22 Apr 2013 15:13:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2013/04/22/398241.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/398241.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2013/04/22/398241.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/398241.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/398241.html</trackback:ping><description><![CDATA[概述<br />原文链接：http://mina.apache.org/mina-project/index.html<br /><br />Apache MINA 是一个网络应用框架， 它可以帮助你简单容易的开发高性能，高可扩展性的网络应用程序。Apache MINA底层利用Java NIO实现，在TCP/IP和UPD/IP等传输层上提供一个抽象的基于事件驱动的异步API。<br /><br />Apache MINA一般被称为：<br /><ul><li>一个NIO框架或库</li></ul><ul><li>客户端，服务器框架或库</li></ul><ul><li>一个网络Socket库</li></ul>尽管如此，Apache MINA要提供的比上面说的多得多。 你可以看一下它的功能特性列表， 利用这些特性你可以快速开发网络应用程序， 你还可以看一下人们是怎么说MINA的。 请下载MINA的包，尝试一下快速开始指南， 浏览一下FAQ或者加入我们的社区。<br /><br />Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at . http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.<br /><br /><img src ="http://www.blogjava.net/mstar/aggbug/398241.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2013-04-22 23:13 <a href="http://www.blogjava.net/mstar/archive/2013/04/22/398241.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Properties.storeToXML方法抛出空指针哦!</title><link>http://www.blogjava.net/mstar/archive/2013/04/19/398100.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Fri, 19 Apr 2013 08:42:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2013/04/19/398100.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/398100.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2013/04/19/398100.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/398100.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/398100.html</trackback:ping><description><![CDATA[今天项目里遇到的, 在这里做个记录!<br /><br />类似下面这段代码:<br /><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">    @Test(expected </span><span style="color: #000000; ">=</span><span style="color: #000000; "> IOException.</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">)<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">void</span><span style="color: #000000; "> testPropertiesStoreToXml() </span><span style="color: #0000FF; ">throws</span><span style="color: #000000; "> IOException {<br />        Properties props </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> Properties();<br />        props.put(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">key1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, </span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">);<br />        ByteArrayOutputStream baos </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> ByteArrayOutputStream();<br />        props.storeToXML(baos,</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">);<br />        String xml </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> String(baos.toByteArray());<br />        Assert.fail(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">should not go to here</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />    }</span></div><br />在生成XML的时候会抛出IOException. 导致这个IOException的是做XMLTransform的时候出现了NullPointerException<br /><br />感觉很奇怪, 调试进Properties的代码看了一下.<br /><br /><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> String getProperty(String key) {<br />    Object oval </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">super</span><span style="color: #000000; ">.get(key);<br />    String sval </span><span style="color: #000000; ">=</span><span style="color: #000000; "> (oval </span><span style="color: #0000FF; ">instanceof</span><span style="color: #000000; "> String) </span><span style="color: #000000; ">?</span><span style="color: #000000; "> (String)oval : </span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">;<br />    </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> ((sval </span><span style="color: #000000; ">==</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">) </span><span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; "> (defaults </span><span style="color: #000000; ">!=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)) </span><span style="color: #000000; ">?</span><span style="color: #000000; "> defaults.getProperty(key) : sval;<br />    }</span></div><br />原来Properties这货, 不是String的属性一码色的返回NULL啊.<br /><br />结果在XMLTransform的时候, 直接对这个NULL进行方法调用.<br /><br />后来看了一下Properties文档, Properties继承至Hashtable, 所以有put和putAll之类的方法. 但是不建议使用, <br />因为这些方法不限定String类型. 推荐使用setProperty方法, 这个方法的值一定是String.<br /><br /><span style="background-color: rgb(211, 211, 211);">Because <code>Properties</code> inherits from <code>Hashtable</code>, the
 <code>put</code> and <code>putAll</code> methods can be applied to a
 <code>Properties</code> object.  Their use is strongly discouraged as they
 allow the caller to insert entries whose keys or values are not
 <code>Strings</code>.  The <code>setProperty</code> method should be used
 instead.  If the <code>store</code> or <code>save</code> method is called
 on a "compromised" <code>Properties</code> object that contains a
 non-<code>String</code> key or value, the call will fail. Similarly, 
 the call to the <code>propertyNames</code> or <code>list</code> method 
 will fail if it is called on a "compromised" <code>Properties</code> 
 object that contains a non-<code>String</code> key.

 </span><br /><br />OK,我承认是我不好好看文档就用了. 但是我脚的如果你把非String的值调用一下toString再使用不是更好吗?<br /><br /><img src ="http://www.blogjava.net/mstar/aggbug/398100.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2013-04-19 16:42 <a href="http://www.blogjava.net/mstar/archive/2013/04/19/398100.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于spring-mvc的InitBinder注解的参数</title><link>http://www.blogjava.net/mstar/archive/2013/04/17/397945.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Tue, 16 Apr 2013 16:42:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2013/04/17/397945.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/397945.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2013/04/17/397945.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/397945.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/397945.html</trackback:ping><description><![CDATA[通过Spring-mvc的@InitBinder注释的方法可以对WebDataBinder做一些初始化操作。<br />比如设置Validator。 <br />我一直在想能不能为每个Request或者每个Action方法单独设置Validator。<br />也就是说Controller里有多个被@InitBinder标注的方法。 在不同的Action时被分别调用。<br /><br />我注意到了@InitBinder的value参数，<br /><br />api docs里是这样描述的：<br />The names of command/form attributes and/or request parameters
 that this init-binder method is supposed to apply to.
 <p>Default is to apply to all command/form attributes and all request parameters
 processed by the annotated handler class. Specifying model attribute names or
 request parameter names here restricts the init-binder method to those specific
 attributes/parameters, with different init-binder methods typically applying to
 different groups of attributes or parameters. <br /></p><p>是乎是可以针对不同的Form对象或命令调用不同的InitBinder方法。</p><p>于是我写了下面的Controller试了一下</p><p></p><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">@Controller<br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">class</span><span style="color: #000000; "> HomeController {<br />    <br />    </span><span style="color: #0000FF; ">private</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">static</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">final</span><span style="color: #000000; "> Logger logger </span><span style="color: #000000; ">=</span><span style="color: #000000; "> LoggerFactory.getLogger(HomeController.</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">);<br />    <br />    @InitBinder(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">void</span><span style="color: #000000; "> initBinder1(WebDataBinder binder){<br />        logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">initBinder1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />    }<br />    <br />    @InitBinder(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">void</span><span style="color: #000000; "> initBinder2(WebDataBinder binder){<br />        logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">initBinder2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />    }<br />    <br />    </span><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />     * Simply selects the home view to render by returning its name.<br />     </span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />    @RequestMapping(value </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">/</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, method </span><span style="color: #000000; ">=</span><span style="color: #000000; "> RequestMethod.GET)<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> String home(Model model) {        <br />        <br />        Date date </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> Date();<br />        DateFormat dateFormat </span><span style="color: #000000; ">=</span><span style="color: #000000; "> DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);<br />        <br />        String formattedDate </span><span style="color: #000000; ">=</span><span style="color: #000000; "> dateFormat.format(date);<br />        <br />        model.addAttribute(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">serverTime</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, formattedDate );<br />        <br />        </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">home</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;<br />    }<br />    <br />    </span><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />     * Simply selects the home view to render by returning its name.<br />     </span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />    @RequestMapping(value </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">/doit</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, method </span><span style="color: #000000; ">=</span><span style="color: #000000; "> RequestMethod.POST, params</span><span style="color: #000000; ">=</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> String doit1(@RequestParam(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">value1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> value1,<br />            @RequestParam(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) String action, Model model) {        <br />        logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">value1={}</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,value1);<br />        <br />        Date date </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> Date();<br />        DateFormat dateFormat </span><span style="color: #000000; ">=</span><span style="color: #000000; "> DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);<br />        <br />        String formattedDate </span><span style="color: #000000; ">=</span><span style="color: #000000; "> dateFormat.format(date);<br />        <br />        model.addAttribute(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">serverTime</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, formattedDate );<br />        <br />        </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">home</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;<br />    }<br />    <br />    </span><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />     * Simply selects the home view to render by returning its name.<br />     </span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />    @RequestMapping(value </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">/doit</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, method </span><span style="color: #000000; ">=</span><span style="color: #000000; "> RequestMethod.POST, params</span><span style="color: #000000; ">=</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> String doit2(@RequestParam(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">value1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> value1,<br />            @RequestParam(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) String action, Model model) {        <br />        logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">value1={}</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,value1);<br />        <br />        Date date </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> Date();<br />        DateFormat dateFormat </span><span style="color: #000000; ">=</span><span style="color: #000000; "> DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);<br />        <br />        String formattedDate </span><span style="color: #000000; ">=</span><span style="color: #000000; "> dateFormat.format(date);<br />        <br />        model.addAttribute(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">serverTime</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, formattedDate );<br />        <br />        </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">home</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;<br />    }<br />}<br /></span></div><p>画面上的Form是这样的</p><p><br /></p><p></p><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">form </span><span style="color: #FF0000; ">action</span><span style="color: #0000FF; ">="doit"</span><span style="color: #FF0000; "> method</span><span style="color: #0000FF; ">="post"</span><span style="color: #FF0000; "> enctype</span><span style="color: #0000FF; ">="application/x-www-form-urlencoded"</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />    </span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">input </span><span style="color: #FF0000; ">type</span><span style="color: #0000FF; ">="text"</span><span style="color: #FF0000; "> name</span><span style="color: #0000FF; ">="value1"</span><span style="color: #FF0000; "> value</span><span style="color: #0000FF; ">="100"</span><span style="color: #0000FF; ">/&gt;</span><span style="color: #000000; "><br />    </span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">input </span><span style="color: #FF0000; ">type</span><span style="color: #0000FF; ">="submit"</span><span style="color: #FF0000; "> name</span><span style="color: #0000FF; ">="action1"</span><span style="color: #FF0000; "> value</span><span style="color: #0000FF; ">="Action1"</span><span style="color: #0000FF; ">/&gt;</span><span style="color: #000000; "><br />    </span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">input </span><span style="color: #FF0000; ">type</span><span style="color: #0000FF; ">="submit"</span><span style="color: #FF0000; "> name</span><span style="color: #0000FF; ">="action2"</span><span style="color: #FF0000; "> value</span><span style="color: #0000FF; ">="Action2"</span><span style="color: #0000FF; ">/&gt;</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">form</span><span style="color: #0000FF; ">&gt;</span></div><br /><p>我的意愿是如果画面上，点击action1按钮择调用initBinder1方法。 如果点击action2按钮则调用initBinder2方法。</p><p>实际上也确实是这样的。 <br /></p><p>当点击action1时，<span style="color: #000000; ">logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">initBinder1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">); 会执行</span></p><p>当点击action2是，<span style="color: #000000; ">logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">initBinder2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">); 会执行</span></p><p>是乎是可以实现“每个Action方法单独设置Validator”这个目的。</p><p>但是其实并不是这样的。</p><p>我调式进去了InitBinder相关的源代码InitBinderDataBinderFactory， 结果发现它只是在对action这个参数绑定的时候调用了上面这个方法， 对value1绑定的时候那个方法都没有调用。而我们常常要解决的是对同一个参数对于不同的action应用不同的Validator。 <br /></p><p>所以目前还是没有好的方法能直接解决这个问题！</p><p>也许我们可以自己实现一个DataBinderFactory来解决这个问题。</p><p><br /></p><img src ="http://www.blogjava.net/mstar/aggbug/397945.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2013-04-17 00:42 <a href="http://www.blogjava.net/mstar/archive/2013/04/17/397945.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>KMP算法里的next函数是怎么得到的？</title><link>http://www.blogjava.net/mstar/archive/2013/04/14/397824.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Sun, 14 Apr 2013 15:24:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2013/04/14/397824.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/397824.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2013/04/14/397824.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/397824.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/397824.html</trackback:ping><description><![CDATA[今天看KMP算法， 一头雾水！虽然算法的过程是明白了，但是怎么也想不出来怎么证明其中的next函数是怎么得到的。<br />也就是这个'p⑴ p⑵ p⑶…..p(k-1）’ = ' p(j-k+1）p(j-k+2）……p(j-1）’。 为什么找到这个k以后用k的元素比较字符串中i就行了。<br /><br />现在找到一个最接近明白的就是百度百科上的<br /><br />假设<br />主串：s: ‘s⑴ s⑵ s⑶ ……s(n）’ ;<br />模式串 ：p: ‘p⑴ p⑵ p⑶…..p(m）’<br />把课本上的这一段看完后，继续<br />现在我们假设 主串第i个字符与模式串的第j(j&lt;=m）个字符‘失配’后，主串第i个字符与模式串的第k(k&lt;j）个字符继续比较<br />此时，s(i）≠p(j），有<br />主串：s⑴…… s(i-j+1）…… s(i-1） s(i) ………….<br />|| （相配） || ≠（失配）<br />匹配串：p⑴ ...........p(j-1） p(j)<br />由此，我们得到关系式：<br />‘p⑴ p⑵ p⑶…..p(j-1）’ = ’ s(i-j+1）……s(i-1）’<br />由于s(i）≠p(j），接下来s(i）将与p(k）继续比较，则模式串中的前（k-1）个字符的子串必须满足下列关系式，并且不可能存在 k’&gt;k 满足下列关系式：（k&lt;j),<br />‘p⑴ p⑵ p⑶…..p(k-1）’ = ’ s(i-k+1）s(i-k+2）……s(i-1）’<br />即：<br />主串：s⑴……s(i-k +1） s(i-k +2） ……s(i-1） s(i) ………….<br />|| （相配） || ||（有待比较）<br />匹配串：p⑴ p⑵ ……..... p(k-1） p(k)<br />现在我们把前面总结的关系综合一下<br />有：<br />s⑴…s(i-j +1）… s(i-k +1） s(i-k +2） …… s(i-1） s(i) ……<br />|| （相配） || || || ≠（失配）<br />p⑴ ……p(j-k+1） p(j-k+2） …...... p(j-1） p(j)<br />|| （相配） || ||（有待比较）<br />p⑴ p⑵ ……...... p(k-1） p(k)<br />由上，我们得到关系：<br />'p⑴ p⑵ p⑶…..p(k-1）’ = ' p(j-k+1）p(j-k+2）……p(j-1）’<br /><br />不知道是从哪个课本上抄来的。 其实还是不太明白最后一步。<br /><img src ="http://www.blogjava.net/mstar/aggbug/397824.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2013-04-14 23:24 <a href="http://www.blogjava.net/mstar/archive/2013/04/14/397824.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>简单的监视某个端口的连接数的Linux命令</title><link>http://www.blogjava.net/mstar/archive/2012/10/30/linux_shell_watch_connection.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Tue, 30 Oct 2012 01:38:00 GMT</pubDate><guid>http://www.blogjava.net/mstar/archive/2012/10/30/linux_shell_watch_connection.html</guid><wfw:comment>http://www.blogjava.net/mstar/comments/390432.html</wfw:comment><comments>http://www.blogjava.net/mstar/archive/2012/10/30/linux_shell_watch_connection.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/mstar/comments/commentRss/390432.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/mstar/services/trackbacks/390432.html</trackback:ping><description><![CDATA[首先创建一个脚本文件, 我们叫他count_conn吧<br /><br /><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">#</span><span style="color: #000000; ">!/</span><span style="color: #000000; ">bin</span><span style="color: #000000; ">/</span><span style="color: #000000; ">sh<br />netstat </span><span style="color: #000000; ">-</span><span style="color: #000000; ">anp </span><span style="color: #000000; ">|</span><span style="color: #000000; "> grep :$</span><span style="color: #000000; ">1</span><span style="color: #000000; "> </span><span style="color: #000000; ">|</span><span style="color: #000000; "> awk </span><span style="color: #000000; ">'</span><span style="color: #000000; ">{print $5}</span><span style="color: #000000; ">'</span><span style="color: #000000; "> </span><span style="color: #000000; ">|</span><span style="color: #000000; "> awk </span><span style="color: #000000; ">-</span><span style="color: #000000; ">F: </span><span style="color: #000000; ">'</span><span style="color: #000000; ">{print $1}</span><span style="color: #000000; ">'</span><span style="color: #000000; "> </span><span style="color: #000000; ">|</span><span style="color: #000000; "> sort </span><span style="color: #000000; ">|</span><span style="color: #000000; "> uniq </span><span style="color: #000000; ">-</span><span style="color: #000000; ">c<br /></span></div><br />然后执行命令:<br /><br />watch -n 1 count_conn 8080<br /><br />最后的参数就是你要监视的端口.<br /><br /><img src ="http://www.blogjava.net/mstar/aggbug/390432.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/mstar/" target="_blank">黑灵</a> 2012-10-30 09:38 <a href="http://www.blogjava.net/mstar/archive/2012/10/30/linux_shell_watch_connection.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>