﻿<?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-心不停歇，希望就始终存在-随笔分类-java</title><link>http://www.blogjava.net/steven2012/category/51705.html</link><description>专注&amp;坚持</description><language>zh-cn</language><lastBuildDate>Sun, 17 Jun 2012 00:58:49 GMT</lastBuildDate><pubDate>Sun, 17 Jun 2012 00:58:49 GMT</pubDate><ttl>60</ttl><item><title>线程重命名（Netty）和设计模式Decorator</title><link>http://www.blogjava.net/steven2012/archive/2012/06/16/380935.html</link><dc:creator>steven.cui</dc:creator><author>steven.cui</author><pubDate>Sat, 16 Jun 2012 14:32:00 GMT</pubDate><guid>http://www.blogjava.net/steven2012/archive/2012/06/16/380935.html</guid><wfw:comment>http://www.blogjava.net/steven2012/comments/380935.html</wfw:comment><comments>http://www.blogjava.net/steven2012/archive/2012/06/16/380935.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/steven2012/comments/commentRss/380935.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/steven2012/services/trackbacks/380935.html</trackback:ping><description><![CDATA[<p>java的多线程Thread类提供了setName方法或者通过构造器传入name，来指定线程的名称。</p> <p>近些时间在开源方面看到Netty，观察到Netty的重命名线程的策略类：</p> <p>ThreadNameDeterminer。这个接口有两个策略，一个是使用PROPOSED（建议名称），还有个是CURRENT（当前名称）</p> <p>当前名称的策略是未实现的，可能为以后扩展考虑吧。</p> <p>另外就是ThreadRenamingRunnable这个类，这个类里面构建函数传入Runnable接口，和proposed建议名称。</p> <p>由于本身ThreadRenamingRunnable也是实现Runnable类的，所以你在自己业务逻辑种还是照样实现Runnable接口来写逻辑，完全对业务代码没有侵入。</p> <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; ">public</span>&nbsp;run()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">根据规则把线程名字进行修改</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;runnable.run();&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;调用传入接口的run方法</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">finally</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(renamed)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;恢复之前的名字</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div></p> <p><br /></p> <p>只需要在构建的你的Runnable的时候，重新包装一下即可：</p> <p>new <strong>ThreadRenamingRunnable</strong>(new OioWorker(acceptedChannel),</p> <p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<strong>"Old I/O server worker (parentId: " +&nbsp;channel.getId() + ", " + channel + ')'</strong>));</p> <p><br /></p> <p>这样的Decorator模式，重新将Runnable接口进行了&#8220;装饰&#8221;，使其具备了线程名称的功能。</p> <p>Runnable接口还是原来的接口，对run方法的再次封装使其具备了另外一项功能，这就是Decorator模式的精华所在。</p><img src ="http://www.blogjava.net/steven2012/aggbug/380935.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/steven2012/" target="_blank">steven.cui</a> 2012-06-16 22:32 <a href="http://www.blogjava.net/steven2012/archive/2012/06/16/380935.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>判断一个数是否是2的n次幂</title><link>http://www.blogjava.net/steven2012/archive/2012/06/16/380934.html</link><dc:creator>steven.cui</dc:creator><author>steven.cui</author><pubDate>Sat, 16 Jun 2012 14:26:00 GMT</pubDate><guid>http://www.blogjava.net/steven2012/archive/2012/06/16/380934.html</guid><wfw:comment>http://www.blogjava.net/steven2012/comments/380934.html</wfw:comment><comments>http://www.blogjava.net/steven2012/archive/2012/06/16/380934.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/steven2012/comments/commentRss/380934.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/steven2012/services/trackbacks/380934.html</trackback:ping><description><![CDATA[<p>判断一个数是否是2的n次幂</p> <p>类似这样的数字</p> <p>1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 &#8230;</p> <p><br /></p> <p>if ((n &amp; -n) == n)</p> <p>&#8230;</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: #008080; ">1</span>&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Is2Power&nbsp;{<br /><span style="color: #008080; ">2</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;{<br /><span style="color: #008080; ">3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(<span style="color: #0000FF; ">int</span>&nbsp;i&nbsp;=&nbsp;0;i&nbsp;&lt;=&nbsp;1024;&nbsp;i++)&nbsp;{<br /><span style="color: #008080; ">4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;((i&nbsp;&amp;&nbsp;-i)&nbsp;==&nbsp;i)<br /><span style="color: #008080; ">5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(Integer.toBinaryString(i)&nbsp;+&nbsp;",&nbsp;"&nbsp;+&nbsp;Integer.toBinaryString(-i)&nbsp;+&nbsp;"&nbsp;"&nbsp;+&nbsp;i);<br /><span style="color: #008080; ">6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">8</span>&nbsp;}</div></p><img src ="http://www.blogjava.net/steven2012/aggbug/380934.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/steven2012/" target="_blank">steven.cui</a> 2012-06-16 22:26 <a href="http://www.blogjava.net/steven2012/archive/2012/06/16/380934.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>记录一个NonFairSync问题（死锁问题）(LeftRighLock)</title><link>http://www.blogjava.net/steven2012/archive/2012/06/16/380933.html</link><dc:creator>steven.cui</dc:creator><author>steven.cui</author><pubDate>Sat, 16 Jun 2012 14:22:00 GMT</pubDate><guid>http://www.blogjava.net/steven2012/archive/2012/06/16/380933.html</guid><wfw:comment>http://www.blogjava.net/steven2012/comments/380933.html</wfw:comment><comments>http://www.blogjava.net/steven2012/archive/2012/06/16/380933.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/steven2012/comments/commentRss/380933.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/steven2012/services/trackbacks/380933.html</trackback:ping><description><![CDATA[<p>业务上线后，在有大量并发后，出现了一个线程完全被占用的问题，后来通过得到jvm堆栈信息(kill -3)看出来是死锁问题。</p> <p>由于业务逻辑代码实在比较复杂，此处滤掉业务代码把线程竞争关系展示出来：</p> <p><strong>1线程&#8212;&#8212;&#8212;&gt;获得A锁&#8212;&#8212;&#8212;&gt;获得B锁&#8212;&#8212;&#8212;&gt;释放B锁&#8212;&#8212;&#8212;&#8212;&gt;释放A锁</strong></p> <p>2线程&#8212;&#8212;&#8212;&gt;获得A锁&#8212;&#8212;&#8212;&gt;释放A锁</p> <p>3线程-&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&gt;获得B锁&#8212;&#8212;&#8212;&gt;<strong>获得A锁</strong></p> <p><br /></p> <p>问题就出在1和3线程之间的AB锁嵌套导致死锁问题，1线程在没有获得B锁的时候，3线程开始获得B锁然后又得到了A锁，这时候就完全释放不了A锁了，死锁产生了。</p> <p>由于时间关系，问题是理清楚了，只要删掉1线程的A锁就可以了，当时还是仔细了解过是否删除1线程A锁，发现对业务A锁是没必要的。但是线程2会不会也会像刚才一样产生线程死锁呢？不会，因为线程2里并不会得到B锁。</p> <p>1线程&#8212;&#8212;&#8212;&gt;获得B锁&#8212;&#8212;&#8212;&gt;释放B锁</p> <p>2线程-&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&gt;获得A锁&#8212;&#8212;&#8212;&#8212;&gt;释放A锁</p> <p>3线程&#8212;&#8212;&#8212;&gt;获得B锁&#8212;&#8212;&#8212;&gt;获得A锁&#8212;&#8212;&#8212;&#8212;&gt;释放A锁&#8212;&#8212;&#8212;&#8212;&gt;释放B锁</p> <p><br /></p> <p>问题是死锁，但暴露了两部分问题：</p> <p>1.过早的认为自己能控制好竞争关系，对线程间的竞争过早的做出了判断</p> <p>2.每多设计一个锁就增加了一个竞争的因素，尽量小心，一个锁就有可能是一个地雷，一不小心就可能导致严重的问题。</p> <p><br /></p> <p>在<a href="http://book.douban.com/subject/10484692/">《java并发编程实践》</a>这本书中介绍过LeftRightLock，详细了解这个问题的朋友可以去查下这本书的<strong>第十章&nbsp;</strong><strong>避免活跃性危险</strong></p> <p>此书极其详细的介绍了LeftRightLock出现的可能，有可能是因为自己编写程序的疏忽导致，或者由于对锁的认识不足导致，诸多原因都能找到解释。</p><img src ="http://www.blogjava.net/steven2012/aggbug/380933.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/steven2012/" target="_blank">steven.cui</a> 2012-06-16 22:22 <a href="http://www.blogjava.net/steven2012/archive/2012/06/16/380933.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Netty整理和基于Netty封装了一个web game通讯层</title><link>http://www.blogjava.net/steven2012/archive/2012/05/15/378203.html</link><dc:creator>steven.cui</dc:creator><author>steven.cui</author><pubDate>Tue, 15 May 2012 09:09:00 GMT</pubDate><guid>http://www.blogjava.net/steven2012/archive/2012/05/15/378203.html</guid><wfw:comment>http://www.blogjava.net/steven2012/comments/378203.html</wfw:comment><comments>http://www.blogjava.net/steven2012/archive/2012/05/15/378203.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/steven2012/comments/commentRss/378203.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/steven2012/services/trackbacks/378203.html</trackback:ping><description><![CDATA[<p>NIO的理解，请参照：<a href="http://www.goldendoc.org/category/java-nio/">http://www.goldendoc.org/category/java-nio/</a></p> <p>Netty的一些理解，请参照：</p> <p><a href="http://www.kafka0102.com/2010/06/167.html">http://www.kafka0102.com/2010/06/167.html</a></p> <p><a href="http://rdc.taobao.com/team/jm/archives/423">http://rdc.taobao.com/team/jm/archives/423</a></p> <p><br /></p> <p>Netty的高可靠性，可伸缩性，以及效率的确让人着迷，为什么Netty这么快呢？</p> <p>Netty高效的原因：</p> <ol> <li>实现了多路Selector用于读和注册，线程数量是cpu*2，reactor都是这么做的，自己处理写事件，这个我在自己框架中也是这么做的，nio的selector处理注册和读，并且也优化了wakeup，Netty中的wakeup也是优化过的，本身一次wakeup对Nio并不大，但是大批量并发的时候就需要进行优化处理了，只有当selector堵塞的时候进行wakeup，或者说需要下次立刻返回的时候wakeup。</li> <li>Netty在开启多路读写的时候，用的是DirectBuffer，并用了SoftReferrence来做缓存优化，减少传输数据的内存移动和GC。还有预测数据算法，这个具体能不能提高有待讨论</li> <li>并发的控制，基于SEDA的设计理论构建的高效事件模型，真正的异步处理，吞吐量和伸缩性都可以得到保证。</li> </ol> <p><br /></p> <p>nio的实现并不复杂，但想让你的底层通讯，效率，以及可伸缩性和高可靠性做好，还是极具挑战性的。</p> <p><br /></p> <p>目前有个项目是自己写的nio，但效率比起netty来，小了几个数量级，当然以本人一己之力能做到目前这个情况，还算自己满意，也用到生产环境中了，一个web game，及时性要求很高，一台server，5000人没问题。同时广播消息在10000人以内，当然有些优化是在业务逻辑层面的。当然比起netty的效率来讲还是差了几个数量级。</p> <p><br /></p> <p>除了高效，Netty在扩展性方面做的不错：</p> <ol><li>丰富的decoder/encoder实现，你可以轻松的继承一个类实现自己的逻辑，例如游戏中，直接继承FiledLengthBaseFrameDecoder即可。</li> <li>自行添加decoder或者encoder，自由的控制事件流向顺序，通过这个，可以实现一些协议加密解密，协议过滤器，统计工具等等</li> <li>提供很多工具类：Timeout的一些实现，还有ChannelBuffers的一些工具，通常情况下，我们为了减少对Netty的依赖，会自己再封装一层，以完全达到脱离Netty的目的，都会再次封装一层ChannelBuffer，这样目的是不要让上层逻辑跟底层通讯有任何关联，降低耦合，当然也在为考虑更换底层通讯而不影响上层逻辑。</li> <li>提供监听底层消息的ChannelFuture，例如发送完消息可以断开连接等等</li> <li>可调控的通讯架构，可以根据业务的吞吐量来调整，Netty的各项参数不只有socket的一些设置，还能控制事件流顺序和吞吐量的大小等等。</li> </ol> <p><br /></p> <p>最后，基于Netty我简单封装了一个web game所具备的一些GameBuffer，目前比较简陋，后续可能加入一些别的功能。</p> <p><br /></p> <p>项目在:<a href="https://github.com/cuixin/XGameEnginee/">https://github.com/cuixin/XGameEnginee/</a></p> <p><br /></p><img src ="http://www.blogjava.net/steven2012/aggbug/378203.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/steven2012/" target="_blank">steven.cui</a> 2012-05-15 17:09 <a href="http://www.blogjava.net/steven2012/archive/2012/05/15/378203.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>