﻿<?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/jelver/category/35715.html</link><description>每天进步一点点</description><language>zh-cn</language><lastBuildDate>Sat, 21 Aug 2010 19:44:13 GMT</lastBuildDate><pubDate>Sat, 21 Aug 2010 19:44:13 GMT</pubDate><ttl>60</ttl><item><title>java线程控制器实现(转)</title><link>http://www.blogjava.net/jelver/articles/329171.html</link><dc:creator>冰河快狼</dc:creator><author>冰河快狼</author><pubDate>Tue, 17 Aug 2010 23:59:00 GMT</pubDate><guid>http://www.blogjava.net/jelver/articles/329171.html</guid><wfw:comment>http://www.blogjava.net/jelver/comments/329171.html</wfw:comment><comments>http://www.blogjava.net/jelver/articles/329171.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jelver/comments/commentRss/329171.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jelver/services/trackbacks/329171.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: java线程控制器代码分享-根据cpu情况决定线程运行数量和情况原文地址：请点击标题即可。Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->在人人网海量存储系统的存储引擎部分，为了提高CPU和网络的使用情况，使用了ja...&nbsp;&nbsp;<a href='http://www.blogjava.net/jelver/articles/329171.html'>阅读全文</a><img src ="http://www.blogjava.net/jelver/aggbug/329171.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jelver/" target="_blank">冰河快狼</a> 2010-08-18 07:59 <a href="http://www.blogjava.net/jelver/articles/329171.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java nio在多线程环境需注意的问题</title><link>http://www.blogjava.net/jelver/articles/322212.html</link><dc:creator>冰河快狼</dc:creator><author>冰河快狼</author><pubDate>Sat, 29 May 2010 07:53:00 GMT</pubDate><guid>http://www.blogjava.net/jelver/articles/322212.html</guid><wfw:comment>http://www.blogjava.net/jelver/comments/322212.html</wfw:comment><comments>http://www.blogjava.net/jelver/articles/322212.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jelver/comments/commentRss/322212.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jelver/services/trackbacks/322212.html</trackback:ping><description><![CDATA[<p>原帖：<a>http://www.blogjava.net/adapterofcoms/archive/2010/03/02/314242.html</a><br />
<br />
有人说java nio在多线程环境下编程简直就是个恶梦,其实你如果能把握住java nio API的要领,你就可以将之驾驭.&nbsp;</p>
<p>0.&nbsp;一个 channal 对应一个SelectionKey in the same selector.<br />
e.g: <br />
SelectionKey sk=sc.register(selector, SelectionKey.OP_READ, handler);<br />
sk==sc.register(selector, SelectionKey.OP_WRITE, handler) true?<br />
selector.select() 每次返回的对同一channal的sk是否相同?&nbsp;</p>
<p>1.channel.register(...) may <strong>block</strong> if invoked concurrently with another registration[another.register(...)] or selection operation[selector.select(...)] involving *****<strong>the same selector</strong>*****.<br />
这个是register方法jdk src上的原文,<br />
e.g:<br />
如果一个selection thread已经在select方法上等待ing,那么这个时候如果有另一条线程调用channal.register方法的话,那么它将被blocking.<br />
<br />
2.selectionKey.cancel() : The key will be <strong>removed</strong> from all of the selector's key sets <strong>during</strong> *****<strong>the next selection operation[selector.select(...)]</strong>*****.<br />
may <strong>block</strong> briefly if invoked concurrently with a cancellation[cancel()] or selection operation[select(...)] involving ***<strong>the same selector</strong>***.<br />
这个也是cancel方法jdk src上的原文,<br />
e.g:<br />
你先将一个selectionKey.cancel(),然后随即再channel.register to <strong>the same selector</strong>,<br />
在cancel和register之间,如果没有线程(包括当前线程)进行select操作的话,<br />
那么&nbsp;throws java.nio.channels.CancelledKeyException.<br />
所以&nbsp;cancel--&gt;select--&gt;re-register.&nbsp;&nbsp;</p>
<p>3.if <strong>don't remove</strong> the current selectedKey from selector.selectedKeys()[Set]&nbsp;将导致 selector.select(...) <strong>not</strong> <strong>block</strong> [may be cpu 100%,specially when client cut the current channel(connection)].<br />
e.g:<br />
Iterator&lt;SelectionKey&gt; it=selector.selectedKeys().iterator();<br />
...for/while it.hasNext()...<br />
it.remove();<strong>&lt;------*****must do it. or Keys' Set.clear() finally;</strong>&nbsp;</p>
<p>if remove the current selectedKey from selector.selectedKeys()[Set] <strong>but don't</strong> <strong>sk.interestOps(sk.interestOps()&amp; (~sk.readyOps()))</strong>;将导致 selector.select(...) <strong>not block</strong> [select() not block several times, or excepted exception]&nbsp;</p>
<p>4.op_write should not be registered to the selector.&nbsp;&nbsp; [may be cpu100%]&nbsp;</p>
<p>5. if involving&nbsp; wakeup() <strong>before</strong> select() [wakeup called several times &gt;=1],the <strong>next</strong> select() <strong>not block</strong> [not block just once].&nbsp;</p>
<p>尽管以前有些人分析了nio的wakeup性能及not block in linux的bug,但是java nio依然是高效的,那些c/c++的牛人们去看看jre/bin目录下的nio.dll/nio.so吧,java nio是基于select模型(这个是c/c++中常用网络编程模型之一)的.</p>
<p>基于java nio的服务器:mina,girzzly[glassfish],jetty(基于girzzly),tomcat6[可以配置Http11NioProtocol]...</p>
<p>其中从本人对girzzly,tomcat6的源码分析来看,它们都还没有真正发挥出nio异步处理请求的优点,它们的读写还都是blocking的虽然使用了selectorPool,此外tomcat6要剥离出socket通信还要花费一定的功夫.而<strong>mina</strong>却是<strong>名<font class="" style="font-family: " color="#ff0000">不</font>符其实</strong>,还有<strong>bug</strong>哦.</p>
<p><br />
&nbsp;</p>
<img src ="http://www.blogjava.net/jelver/aggbug/322212.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jelver/" target="_blank">冰河快狼</a> 2010-05-29 15:53 <a href="http://www.blogjava.net/jelver/articles/322212.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用NIO实现的一个Chat Demo [转]</title><link>http://www.blogjava.net/jelver/articles/322201.html</link><dc:creator>冰河快狼</dc:creator><author>冰河快狼</author><pubDate>Sat, 29 May 2010 04:38:00 GMT</pubDate><guid>http://www.blogjava.net/jelver/articles/322201.html</guid><wfw:comment>http://www.blogjava.net/jelver/comments/322201.html</wfw:comment><comments>http://www.blogjava.net/jelver/articles/322201.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jelver/comments/commentRss/322201.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jelver/services/trackbacks/322201.html</trackback:ping><description><![CDATA[<p>发现网上找到的许多NIO的用例在跑起来后都有许多问题，最常见的就是没有对interest event进行合理的registry和unregistry，导致程序一直在loopling，又或者当客户端或服务器端连接断开时有死循环的迹象。忍不住自己做了一个demo，我想可以作为一个NIO应用的模板去修改，只要把doRead，doWrite之类的用基于线程的Handler去处理，那就基本可以满足需求了。<br />
这个Demo的目的是在Client和Server间建立类似QQ聊天那样的功能，让客户端和服务器端都支持用户输入和异步消息显示（因为服务器端要支持用户的console输入，所以不要用多个客户端进行连接，否则可能会出现难以预测的问题）。<br />
代码中用红色显示的地方是我认为需要注意的地方，说老实话NIO虽然很强大，但完全用Non-Blocking来编程，有许多需要小心的地方，一不小心还可能造成死循环。就像ReentrantLock之于Synchronized，如果基本的IO能满足需求，就不必强求应用NIO。<br />
注意：OP_WRITE应该是在写入准备就绪的时候才添加到SelectionKey里面去，而且在写入完成后一定要去除，否则selector.select()方法就不会被blocking而造成死循环。<br />
<br />
MyNioServer.java<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td style="background-color: rgb(240,240,240)"><br />
            import java.io.BufferedReader;<br />
            import java.io.IOException;<br />
            import java.io.InputStreamReader;<br />
            import java.util.Iterator;<br />
            import java.util.LinkedList;<br />
            import java.util.Set;<br />
            import java.net.InetAddress;<br />
            import java.net.InetSocketAddress;<br />
            import java.nio.ByteBuffer;<br />
            import java.nio.charset.Charset;<br />
            import java.nio.channels.ServerSocketChannel;<br />
            import java.nio.channels.Selector;<br />
            import java.nio.channels.SelectionKey;<br />
            import java.nio.channels.SocketChannel;<br />
            <br />
            public class MyNioServer {<br />
            <br />
            &nbsp;&nbsp;&nbsp; private int BUFFERSIZE = 1024*10;<br />
            &nbsp;&nbsp;&nbsp; private String CHARSET = "GBK";<br />
            &nbsp;&nbsp;&nbsp; private Selector sel;<br />
            <br />
            &nbsp;&nbsp;&nbsp; public MyNioServer(int port) throws IOException {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ServerSocketChannel ssc = ServerSocketChannel.open();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ssc.configureBlocking(false);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ssc.socket().bind(<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; new InetSocketAddress(InetAddress.getLocalHost(), port));<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sel = Selector.open();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ssc.register(sel, SelectionKey.OP_ACCEPT);<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; public void startup() {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Server start...");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while (!Thread.interrupted()) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int keysCount = sel.select();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Catched " + keysCount + " SelectionKeys");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (keysCount &lt; 1) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; continue;<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Set&lt;SelectionKey&gt; set = sel.selectedKeys();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Iterator&lt;SelectionKey&gt; it = set.iterator();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while (it.hasNext()) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SelectionKey key = it.next();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (key.isAcceptable()) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Key isAcceptable");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; doAccept(key);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (key.isValid() &amp;&amp; key.isReadable()) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Key isReadable");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; doRead(key);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (key.isValid() &amp;&amp; key.isWritable()) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Key isWritable");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; doWrite(key);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;<span style="color: rgb(255,0,0)">&nbsp; set.clear();</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.err.println("Program is interrupted.");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Server stop...");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; shutdown();<br />
            &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; <br />
            &nbsp;&nbsp;&nbsp; public void shutdown(){<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Set&lt;SelectionKey&gt; keys = sel.keys();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for(SelectionKey key:keys){<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; key.channel().close();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sel.close();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; private void doAccept(SelectionKey key) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sc.configureBlocking(false);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: rgb(255,0,0)">SelectionKey newkey = sc.register(sel, SelectionKey.OP_READ);</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; newkey.attach(new LinkedList&lt;ByteBuffer&gt;());<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; new Thread(new UserInteractive(newkey)).start();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.err.println("Failed to accept new client.");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("end doAccept");<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; // TODO buffersize performance testing<br />
            &nbsp;&nbsp;&nbsp; private void doRead(SelectionKey key) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SocketChannel sc = (SocketChannel) key.channel();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ByteBuffer bb = ByteBuffer.allocate(BUFFERSIZE);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; StringBuffer sb = new StringBuffer();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int count = 0;<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while ( (count = sc.read(bb)) &gt; 0) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)"> bb.flip();</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sb.append(Charset.forName(CHARSET).decode(bb));<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)"> bb.flip();</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //if client disconnected, read return -1<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: rgb(255,0,0)">if(count == -1){</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("client disconnected");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<span style="color: rgb(255,0,0)"> disconnect(key);&nbsp;&nbsp;&nbsp; </span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } else {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("message received from client:" + sb.toString());<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: rgb(255,0,0)">disconnect(key);</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("end doRead");<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; private void doWrite(SelectionKey key) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SocketChannel sc = (SocketChannel) key.channel();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; LinkedList&lt;ByteBuffer&gt; outseq = (LinkedList&lt;ByteBuffer&gt;) key<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .attachment();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ByteBuffer bb = outseq.poll();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(bb == null){<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while(bb.hasRemaining()){<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sc.write(bb);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: rgb(255,0,0)">disconnect(key);</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (outseq.size() == 0) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("after all buffers wrote, unregister OP_WRITE from interestOps");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: rgb(255,0,0)">key.interestOps(SelectionKey.OP_READ);</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("end doWrote");<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; private void disconnect(SelectionKey key) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; key.channel().close();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; //TODO find out how to shutdown<br />
            &nbsp;&nbsp;&nbsp; private class UserInteractive implements Runnable {<br />
            <br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SelectionKey key;<br />
            <br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public UserInteractive(SelectionKey key) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.key = key;<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void run() {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("UserInteractive thread start...");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; BufferedReader br = new BufferedReader(new InputStreamReader(<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.in));<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while (true) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; String inputLine = br.readLine();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ByteBuffer bb = ByteBuffer.allocate(BUFFERSIZE);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; bb = ByteBuffer.wrap(inputLine.getBytes());<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ((LinkedList&lt;ByteBuffer&gt;) key.attachment()).offer(bb);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .println("after input, register OP_WRITE to interestOps and wakeup selector");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: rgb(255,0,0)">key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: rgb(255,0,0)">key.selector().wakeup();</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; /**<br />
            &nbsp;&nbsp;&nbsp; &nbsp;* @param args<br />
            &nbsp;&nbsp;&nbsp; &nbsp;*/<br />
            &nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; MyNioServer server = new MyNioServer(10001);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; server.startup();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (Exception e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.err.println("Exception caught, program exiting&#8230;");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }<br />
            }<br />
            <br />
            </td>
        </tr>
    </tbody>
</table>
<br />
MyNioClient.java<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td style="background-color: rgb(240,240,240)"><br />
            import java.io.BufferedReader;<br />
            import java.io.IOException;<br />
            import java.io.InputStreamReader;<br />
            import java.net.InetAddress;<br />
            import java.net.InetSocketAddress;<br />
            import java.nio.ByteBuffer;<br />
            import java.nio.CharBuffer;<br />
            import java.nio.charset.Charset;<br />
            import java.nio.channels.Selector;<br />
            import java.nio.channels.SocketChannel;<br />
            import java.nio.channels.SelectionKey;<br />
            import java.text.MessageFormat;<br />
            import java.util.LinkedList;<br />
            import java.util.Set;<br />
            import java.util.Iterator;<br />
            <br />
            public class MyNioClient {<br />
            <br />
            &nbsp;&nbsp;&nbsp; private int BUFFERSIZE = 1024*10;<br />
            &nbsp;&nbsp;&nbsp; private String CHARSET = "GBK";<br />
            &nbsp;&nbsp;&nbsp; private Selector sel;<br />
            <br />
            &nbsp;&nbsp;&nbsp; public MyNioClient(int port) throws IOException {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SocketChannel sc = SocketChannel.open();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sc.configureBlocking(false);&nbsp;&nbsp;&nbsp; // this operation need to be executed before socket.connnect, for OP_CONNECT event<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sc.connect(new InetSocketAddress(InetAddress.getLocalHost(), port));<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sel = Selector.open();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sc.register(sel, SelectionKey.OP_CONNECT |SelectionKey.OP_READ);<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; public void startup() {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Client start...");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while (!Thread.interrupted()) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int keysCount = sel.select();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Catched " + keysCount + " SelectionKeys");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (keysCount &lt; 1) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; continue;<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Set&lt;SelectionKey&gt; selectedKeys = sel.selectedKeys();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Iterator&lt;SelectionKey&gt; it = selectedKeys.iterator();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while (it.hasNext()) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SelectionKey key = it.next();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //printKeyInfo(key);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (key.isConnectable()) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Key isConnectable");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; doConnect(key);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } else if (key.isValid() &amp;&amp; key.isReadable()) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Key isReadable");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; doRead(key);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } else if (key.isValid() &amp;&amp; key.isWritable()) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Key isWritable");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; doWrite(key);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; selectedKeys.clear();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.err.println("Program is interrupted.");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("Client stop...");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; shutdown();<br />
            &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; <br />
            &nbsp;&nbsp;&nbsp; public void shutdown(){<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Set&lt;SelectionKey&gt; keys = sel.keys();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for(SelectionKey key:keys){<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; key.channel().close();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sel.close();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; private void printKeyInfo(SelectionKey key) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; String keyStr = MessageFormat<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .format(<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "IntOps:{0},ReadyOps:{1},isVal:{2},isAcc:{3},isCnn:{4},isRead:{5},isWrite:{6}",<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; key.interestOps(), key.readyOps(), key.isValid(), key<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .isAcceptable(), key.isConnectable(), key<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .isReadable(), key.isWritable());<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println(keyStr);<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; private void doConnect(SelectionKey key) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: rgb(255,0,0)">boolean flag = ((SocketChannel) key.channel()).finishConnect();</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.exit(1);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("unregister OP_CONNECT from interestOps");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: rgb(255,0,0)">key.interestOps(SelectionKey.OP_READ);</span><br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; key.attach(new LinkedList&lt;ByteBuffer&gt;());<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; new Thread(new UserInteractive(key)).start();<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; private void doRead(SelectionKey key) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SocketChannel sc = (SocketChannel) key.channel();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ByteBuffer bb = ByteBuffer.allocate(BUFFERSIZE);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; StringBuffer sb = new StringBuffer();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while (sc.read(bb) &gt; 0) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; bb.flip(); <br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sb.append(Charset.forName(CHARSET).decode(bb));<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; bb.flip();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("message received from server:" + sb.toString());<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; disconnect(key);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.exit(1);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("now end readMessage");<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; private void doWrite(SelectionKey key) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SocketChannel sc = (SocketChannel) key.channel();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; LinkedList&lt;ByteBuffer&gt; outseq = (LinkedList&lt;ByteBuffer&gt;) key<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .attachment();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ByteBuffer bb = outseq.poll();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(bb == null){<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while(bb.hasRemaining()){<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sc.write(bb);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; disconnect(key);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (outseq.size() == 0) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("after all buffers wrote, unregister OP_WRITE from interestOps");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; key.interestOps(SelectionKey.OP_READ);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out.println("end doWrote");<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; private void disconnect(SelectionKey key) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; key.channel().close();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; private class UserInteractive implements Runnable {<br />
            <br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SelectionKey key;<br />
            <br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public UserInteractive(SelectionKey key) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; this.key = key;<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public void run() {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; LinkedList&lt;ByteBuffer&gt; outseq = (LinkedList&lt;ByteBuffer&gt;) key<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .attachment();<br />
            &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; BufferedReader br = new BufferedReader(new InputStreamReader(System.in));<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while (true) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; String inputLine = br.readLine();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if ("quit".equalsIgnoreCase(inputLine)) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; key.channel().close();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.exit(1);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ByteBuffer bb = ByteBuffer.allocate(BUFFERSIZE);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; bb = ByteBuffer.wrap(inputLine.getBytes());<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; outseq.offer(bb);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.out<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .println("after input, register OP_WRITE to interestOps and wakeup selector");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; key.interestOps(SelectionKey.OP_READ<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; | SelectionKey.OP_WRITE);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sel.wakeup();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (IOException e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            &nbsp;&nbsp;&nbsp; /**<br />
            &nbsp;&nbsp;&nbsp; &nbsp;* @param args<br />
            &nbsp;&nbsp;&nbsp; &nbsp;*/<br />
            &nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; try {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; MyNioClient client = new MyNioClient(10001);<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; client.startup();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } catch (Exception e) {<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; e.printStackTrace();<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.err.println("Exception caught, program exiting...");<br />
            &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
            &nbsp;&nbsp;&nbsp; }<br />
            <br />
            }<br />
            </td>
        </tr>
    </tbody>
</table>
</p>
<img src ="http://www.blogjava.net/jelver/aggbug/322201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jelver/" target="_blank">冰河快狼</a> 2010-05-29 12:38 <a href="http://www.blogjava.net/jelver/articles/322201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Java Socket网络编程的经典例子(转)</title><link>http://www.blogjava.net/jelver/articles/280175.html</link><dc:creator>冰河快狼</dc:creator><author>冰河快狼</author><pubDate>Fri, 05 Jun 2009 03:19:00 GMT</pubDate><guid>http://www.blogjava.net/jelver/articles/280175.html</guid><wfw:comment>http://www.blogjava.net/jelver/comments/280175.html</wfw:comment><comments>http://www.blogjava.net/jelver/articles/280175.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jelver/comments/commentRss/280175.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jelver/services/trackbacks/280175.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;事实上网络编程简单的理解就是两台计算机相互通讯数据而已，对于程序员而言，去掌握一种编程接口并使用一种编程模型相对就会显得简单的多了，Java&nbsp;SDK提供一些相对简单的Api来完成这些工作。Socket就是其中之一，对于Java而言，这些Api存在与java.net&nbsp;这个包里面，因此只要导入这个包就可以准备网络编程了。&nbsp;网络编程的基本模型就是客户机到...&nbsp;&nbsp;<a href='http://www.blogjava.net/jelver/articles/280175.html'>阅读全文</a><img src ="http://www.blogjava.net/jelver/aggbug/280175.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jelver/" target="_blank">冰河快狼</a> 2009-06-05 11:19 <a href="http://www.blogjava.net/jelver/articles/280175.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Scalable io in java 转</title><link>http://www.blogjava.net/jelver/articles/254389.html</link><dc:creator>冰河快狼</dc:creator><author>冰河快狼</author><pubDate>Thu, 12 Feb 2009 06:35:00 GMT</pubDate><guid>http://www.blogjava.net/jelver/articles/254389.html</guid><wfw:comment>http://www.blogjava.net/jelver/comments/254389.html</wfw:comment><comments>http://www.blogjava.net/jelver/articles/254389.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jelver/comments/commentRss/254389.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jelver/services/trackbacks/254389.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 原文http://blog.csdn.net/liu251/archive/2008/07/06/2618752.aspx本文可看成是对Doug Lea Scalable IO in Java一文的翻译。当前分布式计算　Web Services盛行天下，这些网络服务的底层都离不开对socket的操作。他们都有一个共同的结构： 1. Read request 2. Decode reques...&nbsp;&nbsp;<a href='http://www.blogjava.net/jelver/articles/254389.html'>阅读全文</a><img src ="http://www.blogjava.net/jelver/aggbug/254389.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jelver/" target="_blank">冰河快狼</a> 2009-02-12 14:35 <a href="http://www.blogjava.net/jelver/articles/254389.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网络在线游戏开发心得(服务器端) 转贴</title><link>http://www.blogjava.net/jelver/articles/239470.html</link><dc:creator>冰河快狼</dc:creator><author>冰河快狼</author><pubDate>Sat, 08 Nov 2008 15:14:00 GMT</pubDate><guid>http://www.blogjava.net/jelver/articles/239470.html</guid><wfw:comment>http://www.blogjava.net/jelver/comments/239470.html</wfw:comment><comments>http://www.blogjava.net/jelver/articles/239470.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jelver/comments/commentRss/239470.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jelver/services/trackbacks/239470.html</trackback:ping><description><![CDATA[<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">一个多人在线的棋牌类<a href="http://diy.21tx.com/net/" target="_blank">网络</a><a href="http://games.21tx.com/" target="_blank">游戏</a>的项目临近尾声，我参与了该项目的整个设计流程，并且完成了90%的核心代码。关于这个项目，有很多地方值得聊一聊。本系列不打算把这个项目将得多么详细规范，那是设计文档应该描述的，我打算只说说一些值得注意的地方。这个项目的一个特别之处是，客户端是<a href="http://mobile.21tx.com/" target="_blank">手机</a>，用户通过移动网络与<a href="http://www.21tx.com/server/" target="_blank">服务器</a><a href="http://news.21tx.com/telcom/" target="_blank">通信</a>。和PC相比，手机的处理能力极弱，而且网络流量费用昂贵。因为除了要考虑普通<a href="http://games.21tx.com/netgames/" target="_blank">网络游戏</a>的一些问题之外，这两点也需要在设计中充分考虑。首先是<a href="http://dev.21tx.com/language/" target="_blank">开发语言</a>的选择，由于服务器是<a href="http://dev.21tx.com/os/linux/" target="_blank">Linux</a>的环境，MS的技术直接排除，至于MONO嘛，我实在不放心。可供选择的是<a href="http://dev.21tx.com/language/c/" target="_blank">C++</a>和<a href="http://dev.21tx.com/java/" target="_blank">Java</a>，Java胜在网络能力强大，开发周期短，有众多框架和开源库的支持，要写出烂得不可接受的代码也不容易；C++则胜在速度快。综合各方面因素，C++更容易把这个项目变成一堆代码噩梦，我们选择了Java。</span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; line-height: 150%; text-align: left; tab-stops: list 21.0pt" align="left"><strong><span style="color: black; line-height: 150%; font-family: 宋体">一、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="color: black; line-height: 150%; font-family: 宋体">网络</span></strong></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">网络游戏，首先面临的问题当然是如何进行网络通信。首先考虑的是HTTP协议，因为所有的<a href="http://dev.21tx.com/java/j2me/" target="_blank">J2ME</a>手机都支持这个，我们当然想尽可能的兼容用户。而且HTTP协议封装程度已经非常高了，不用去考虑线程、同步、状态管理、连接池，不过HTTP协议有两个不爽的地方：</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">◇&nbsp;协议无状态，这个问题已经困扰过很多人很多次了。我曾考虑过的解决办法是改造HTTP协议，在数据传输完成之后不关闭socket，但是这样做工作量非常大，在项目周期中，基本上就是Mission impossible，不予考虑。那么客户也就只能通过轮询的方式向服务器请求数据。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">◇&nbsp;网络流量过大。就这个项目来说，网络间传递的只是指令，但是每次传递都要加上一堆毫无用处的HTTP Head，再加上客户端需要做轮询，这个流量对于手机来说简直恐怖，经简单测试，按照0.03元/K的GPRS网络费用计算，一局牌居然要消耗1元多的费用（每秒轮询），实在不可接受。也许我们可以采用流量费包月的资费方式，不过这个话题与技术无关。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">以上问题导致我们选择了Socket，这意味着我们将没有一个<a href="http://dev.21tx.com/web/" target="_blank">Web</a>环境，很多东西都要靠自己去实现：线程管理、客户状态监控、对象池、控制台&#8230;&#8230;&#8230;.网络部分打算采用Java NIO<clk>来实现，这是一种新的网络监听方式，基于事件的异步通信，可以提高<nobr oncontextmenu="return false" onmousemove="kwM(0)" id="clickeyekey0" onmouseover="kwE(event,0, this)" style="background: url(http://control.clickeye.com.cn/images/line5.gif) repeat-x 50% bottom; padding-bottom: 2px; color: #6600ff" onclick="kwC(event,0)" onmouseout="kwL(event,this)">性能</nobr><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" src="http://images.clickeye.com.cn/images/window.gif"  alt="" />。每个客户端连接之后，会有一个独立的</clk>SocketChannel与它通信，这个SocketChannel会在用户的整个生存周期中存在。用户如果断开连接，服务器会得到-1，并且会抛出Connection reset异常，通过捕获这两个特征，可以在用户意外断开连接后清理相关的资源。由于NIO是异步通信的，所以没有复杂的线程管理。</span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; line-height: 150%; text-align: left; tab-stops: list 21.0pt" align="left"><strong><span style="color: black; line-height: 150%; font-family: 宋体">二、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="color: black; line-height: 150%; font-family: 宋体">通信协议</span></strong></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">这个项目并没有复杂的通信指令，命令数量很有限，但是还是有个关键问题需要关注：流量。为了尽量减小流量，我们使用字节代替字符串来保存系统指令，这样可以使流量减少一半，比如使用一个字节来保存一张扑克牌，字节高位表示花色，字节低位表示数字，如果0代表黑桃，那么黑桃三就应该是0x03，这个需要靠位操作来实现：</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">int m=0;</span></p>
<p style="margin: 0cm 0cm 0pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">&nbsp;&nbsp;&nbsp; int n=3;</span></p>
<p style="margin: 0cm 0cm 0pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">&nbsp;&nbsp;&nbsp; byte card=(byte)(m)&lt;&lt;4)|((byte)n;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //m</span><span style="color: black; line-height: 150%; font-family: 宋体">左移四位，然后与n左或操作</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">游戏中需要传递用户的积分，这是一个大整数，使用四个字节来保存比较保险，将整数转换为四个字节的操作如下：</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">&nbsp;</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img id="Codehighlighter1_45_175_Open_Image" onclick="this.style.display='none'; Codehighlighter1_45_175_Open_Text.style.display='none'; Codehighlighter1_45_175_Closed_Image.style.display='inline'; Codehighlighter1_45_175_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_45_175_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_45_175_Closed_Text.style.display='none'; Codehighlighter1_45_175_Open_Image.style.display='inline'; Codehighlighter1_45_175_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">byte</span><span style="color: #000000">[]&nbsp;translateLong(</span><span style="color: #0000ff">long</span><span style="color: #000000">&nbsp;mark)</span><span id="Codehighlighter1_45_175_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_45_175_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">byte</span><span style="color: #000000">[]&nbsp;b&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">byte</span><span style="color: #000000">[</span><span style="color: #000000">4</span><span style="color: #000000">];<br />
<img id="Codehighlighter1_106_159_Open_Image" onclick="this.style.display='none'; Codehighlighter1_106_159_Open_Text.style.display='none'; Codehighlighter1_106_159_Closed_Image.style.display='inline'; Codehighlighter1_106_159_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_106_159_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_106_159_Closed_Text.style.display='none'; Codehighlighter1_106_159_Open_Image.style.display='inline'; Codehighlighter1_106_159_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;i&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">4</span><span style="color: #000000">;&nbsp;i</span><span style="color: #000000">++</span><span style="color: #000000">)</span><span id="Codehighlighter1_106_159_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_106_159_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b[i]&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">byte</span><span style="color: #000000">)&nbsp;(mark&nbsp;</span><span style="color: #000000">&gt;&gt;&gt;</span><span style="color: #000000">&nbsp;(</span><span style="color: #000000">24</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">8</span><span style="color: #000000">));<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;b;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span></div>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"></span>&nbsp;</p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21.75pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">将四个字节转回来的操作如下：</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21.75pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">&nbsp;</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img id="Codehighlighter1_42_191_Open_Image" onclick="this.style.display='none'; Codehighlighter1_42_191_Open_Text.style.display='none'; Codehighlighter1_42_191_Closed_Image.style.display='inline'; Codehighlighter1_42_191_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_42_191_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_42_191_Closed_Text.style.display='none'; Codehighlighter1_42_191_Open_Image.style.display='inline'; Codehighlighter1_42_191_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">long</span><span style="color: #000000">&nbsp;translateByte(</span><span style="color: #0000ff">byte</span><span style="color: #000000">[]&nbsp;b)</span><span id="Codehighlighter1_42_191_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_42_191_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;mask&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0xff</span><span style="color: #000000">;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;temp&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;res&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img id="Codehighlighter1_121_176_Open_Image" onclick="this.style.display='none'; Codehighlighter1_121_176_Open_Text.style.display='none'; Codehighlighter1_121_176_Closed_Image.style.display='inline'; Codehighlighter1_121_176_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_121_176_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_121_176_Closed_Text.style.display='none'; Codehighlighter1_121_176_Open_Image.style.display='inline'; Codehighlighter1_121_176_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;i&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">4</span><span style="color: #000000">;&nbsp;i</span><span style="color: #000000">++</span><span style="color: #000000">)&nbsp;</span><span id="Codehighlighter1_121_176_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_121_176_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res&nbsp;</span><span style="color: #000000">&lt;&lt;=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">8</span><span style="color: #000000">;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;b[i]&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">&nbsp;mask;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res&nbsp;</span><span style="color: #000000">|=</span><span style="color: #000000">&nbsp;temp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;res;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span></div>
<p style="margin: 0cm 0cm 0pt; text-indent: 21.75pt; line-height: 150%; text-align: left" align="left"></span>&nbsp;</p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; line-height: 150%; text-align: left; tab-stops: list 21.0pt" align="left"><strong><span style="color: black; line-height: 150%; font-family: 宋体">三、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="color: black; line-height: 150%; font-family: 宋体"><a href="http://dev.21tx.com/database/" target="_blank">数据库</a>连接池</span></strong></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">由于没有一个web环境，所以我们需要自己实现一个数据库连接池，apache有一个项目叫做commons DBCP，这是一个基于apache自己的对象池（apache commons pool）实现的数据库连接池，我们可以直接拿来使用，apache的软件未必是最好的，但是极大可能比我们自己写的要好。Commons DBCP需要三个.jar：commons-collections-3.1.jar、commons-dbcp-1.2.1.jar、commons-pool-1.2.jar这三个文件都可以在apache &#8211; Jakarta &#8211; commons项目下<a href="http://dl.21tx.com/" target="_blank">下载</a>，加入到工程中即可。构造一个数据库连接池的代码如下：</span></p>
<p style="margin: 0cm 0cm 0pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">&nbsp;</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.sql.</span><span style="color: #000000">*</span><span style="color: #000000">;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;com.gwnet.games.antiLord.util.</span><span style="color: #000000">*</span><span style="color: #000000">;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;org.apache.commons.dbcp.ConnectionFactory;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;org.apache.commons.dbcp.BasicDataSource;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;org.apache.commons.dbcp.DataSourceConnectionFactory;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;BasicDataSource&nbsp;bds</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;BasicDataSource();<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;ConnectionFactory&nbsp;fac</span><span style="color: #000000">=</span><span style="color: #0000ff">null</span><span style="color: #000000">;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">初始化连接池</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />bds.setDriverClassName(&#8220;org.postgresql.Driver&#8221;);&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">数据库驱动程序</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />bds.setUrl(&#8220;JDBC:postgresql:</span><span style="color: #008000">//</span><span style="color: #008000">localhost:5432/myDB&#8221;);&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">数据库url</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />bds.setUsername(&#8220;postgres&#8221;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">dba帐号</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />bds.setPassword(&#8220;XXXXXXXX&#8221;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">密码</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />bds.setInitialSize(</span><span style="color: #000000">100</span><span style="color: #000000">);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">初始化连接数量</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />bds.setMaxIdle(</span><span style="color: #000000">10</span><span style="color: #000000">);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">最大idle数</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />bds.setMaxWait(</span><span style="color: #000000">1000</span><span style="color: #000000">*</span><span style="color: #000000">60</span><span style="color: #000000">);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">超时回收时间</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />fac</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;DataSourceConnectionFactory(bds);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">得到连接工厂</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />Connection&nbsp;conn</span><span style="color: #000000">=</span><span style="color: #000000">fac.createConnection();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">从池中获得连接</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />conn.close();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">释放连接，回到池中<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #008000">//</span><span style="color: #008000">销毁连接池</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />bds.close();<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />bds</span><span style="color: #000000">=</span><span style="color: #0000ff">null</span><span style="color: #000000">;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />fac</span><span style="color: #000000">=</span><span style="color: #0000ff">null</span><span style="color: #000000">;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span></div>
<p style="margin: 0cm 0cm 0pt; line-height: 150%; text-align: left" align="left"></span><span style="color: black; line-height: 150%; font-family: 宋体">请自行处理操作中的各种异常。</span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; line-height: 150%; text-align: left; tab-stops: list 21.0pt" align="left"><strong><span style="color: black; line-height: 150%; font-family: 宋体">四、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="color: black; line-height: 150%; font-family: 宋体">扑克牌的生成</span></strong></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">游戏中需要为用户生成随机的扑克牌，首先我们需要初始化一副牌，放到一个Hashmap中，每张牌以一个字节表示，高为代表花色，的为代表数字，生成整副牌：</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体"></p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;HashMap&nbsp;cards&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;HashMap();<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;tmp</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img id="Codehighlighter1_86_227_Open_Image" onclick="this.style.display='none'; Codehighlighter1_86_227_Open_Text.style.display='none'; Codehighlighter1_86_227_Closed_Image.style.display='inline'; Codehighlighter1_86_227_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_86_227_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_86_227_Closed_Text.style.display='none'; Codehighlighter1_86_227_Open_Image.style.display='inline'; Codehighlighter1_86_227_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;i&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">4</span><span style="color: #000000">;&nbsp;i</span><span style="color: #000000">++</span><span style="color: #000000">)&nbsp;</span><span id="Codehighlighter1_86_227_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_86_227_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img id="Codehighlighter1_118_224_Open_Image" onclick="this.style.display='none'; Codehighlighter1_118_224_Open_Text.style.display='none'; Codehighlighter1_118_224_Closed_Image.style.display='inline'; Codehighlighter1_118_224_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_118_224_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_118_224_Closed_Text.style.display='none'; Codehighlighter1_118_224_Open_Image.style.display='inline'; Codehighlighter1_118_224_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" /></span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;m&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;m&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">13</span><span style="color: #000000">;&nbsp;m</span><span style="color: #000000">++</span><span style="color: #000000">)&nbsp;</span><span id="Codehighlighter1_118_224_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_118_224_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />tmp</span><span style="color: #000000">=</span><span style="color: #000000">((</span><span style="color: #0000ff">byte</span><span style="color: #000000">)(i)</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">4</span><span style="color: #000000">)</span><span style="color: #000000">|</span><span style="color: #000000">((</span><span style="color: #0000ff">byte</span><span style="color: #000000">)m);&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">使用位操作构造一张牌</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />cards.put(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Integer(i&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">13</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;m),</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Byte((</span><span style="color: #0000ff">byte</span><span style="color: #000000">)tmp));<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />cards.put(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Integer(</span><span style="color: #000000">53</span><span style="color: #000000">),&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Byte((</span><span style="color: #0000ff">byte</span><span style="color: #000000">)</span><span style="color: #000000">0x4d</span><span style="color: #000000">));&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">大王</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />cards.put(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Integer(</span><span style="color: #000000">54</span><span style="color: #000000">),&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Byte((</span><span style="color: #0000ff">byte</span><span style="color: #000000">)</span><span style="color: #000000">0x4e</span><span style="color: #000000">));&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">小王</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span></div>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left">如何随机地得到其中的N张牌呢？我们的做法是生成一个0-55的随机数，用这个随机数作主键从Hashmap中获得对象，取得之后，把该对象从队列中删除，以免重复取得。由于java中的随机数是根据时间生成的，所以有可能导致用户得到的牌不够散，每个用户都摸到一条龙岂不是笑话？所以在生成随机数的时候我们加入了一个大素数来作运算：</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">long cardId=new Long((Math.round(Math.random() * 87) % 55)).intValue();</span><span style="color: black; line-height: 150%; font-family: 宋体">通过修改这个大素数，可以控制某个用户的牌比较好。</span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; line-height: 150%; text-align: left; tab-stops: list 21.0pt" align="left"><strong><span style="color: black; line-height: 150%; font-family: 宋体">五、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="color: black; line-height: 150%; font-family: 宋体">线程</span></strong></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">实际上本系统并没有复杂的线程管理，但是我想提供一个控制台让管理员可以管理游戏主线程，可以让它停止、中段、恢复、重启动，本来的设计是管理员通过与线程A打交道，通过A去管理主线程B，但是熟悉java线程的朋友都知道，线程互相管理基本上就是不实际的，举个最简单的例子，A如何销毁B？也许你会说调用B的destroy()方法就好了，网上很多讲解java线程的资料也确实是这么说的，但是他们都是鬼扯的，自己去看看java源代码吧，Thread.destroy()方法的实际代码如下：</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">public void destroy() </span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">{</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">&nbsp;&nbsp;&nbsp; throw new NoSuchMethodError();</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">}</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">事实真相是，Thread.destroy()方法自始至终就没有被实现过。所有写文章，教别人用这个方法销毁线程的人，都去撞墙吧，丢人丢大了。最好的办法是A负责生成一个B并且启动它，然后B自己管理生存周期，A和B通过使用可共享的方法来通信，这是sun推荐的做法。</span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; line-height: 150%; text-align: left; tab-stops: list 21.0pt" align="left"><strong><span style="color: black; line-height: 150%; font-family: 宋体">六、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="color: black; line-height: 150%; font-family: 宋体">异步消息</span></strong></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">用户玩牌的过程中，有很多东西需要记录下来，比如记录用户的积分、等级变化，记录玩牌日志供数据统计等，当用户数量很多的时候，在数据库中记录这些信息会很耗费资源，用户玩了一局之后会可能会等待很长时间。解决这个问题的方法是利用<a href="http://dev.21tx.com/java/j2ee/" target="_blank">J2EE</a>的消息bean来提供异步通信的机制，需要记录数据的时候，系统会封装一个值对象，发送给J2EE容器，这个操作是很快的，完成之后就返回，用户可以继续操作，不用关心消息何时被处理。J2EE的消息框架具备如下特征：</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">◇消息一定会被阅读，而且只阅读一次。JMS框架有自己的算法，把消息缓冲到<a href="http://diy.21tx.com/hdd/" target="_blank">硬盘</a>，就算J2EE服务器死掉，消息也不会丢失。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">◇系统采用点对点的Queue消息队列，可以保证同等优先级的消息先进先出。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">在Jboss 4.0中，部署消息Bean和Queue队列，都比weblogic 8.1来的容易，只需要在jboss.<a href="http://dev.21tx.com/web/xml/" target="_blank">XML</a>中声明消息目的地，如果jboss发现该目的地不存在的话，会自动建立一个，实在很简单。关于消息bean的开发与部署，我有专门的文章描述。</span></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt; line-height: 150%; text-align: left; tab-stops: list 21.0pt" align="left"><strong><span style="color: black; line-height: 150%; font-family: 宋体">七、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span style="color: black; line-height: 150%; font-family: 宋体">启动与退出</span></strong></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">为了让系统具备让人满意的性能，应该尽量多的重用对象，减少创建新对象。比如上面提到的消息发送，我们的操作是提供一个静态类，在系统启动的时候就初始化，保持与JMS服务器的连接，系统发送消息的时候，不用再去查询JNDI和生成QueueConnectionFactory，这样可以提高系统响应速度。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">在数据库连接池的问题上，我们也采用同样的操作，启动的时候初始化N个连接。但是如果在关闭进程的时候不做任何操作，会导致JMS抛出socket异常，虽然没什么大的影响，但总显得不专业，而且池中的连接不被释放的话，也可能导致问题。最好能够让系统像jboss等控制台程序一样，ctrl+c之后能够执行操作，释放资源再退出。我们可以通过给进程/线程加上一个Hook来实现，<a href="http://dev.21tx.com/os/windows/" target="_blank">Windows</a>程序员应该对这个非常熟悉。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">Hook</span><span style="color: black; line-height: 150%; font-family: 宋体">应该是一个线程方法，如下：</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">public class Hook extends Thread</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">{</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">&nbsp;&nbsp;&nbsp; public void run()</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span><span style="color: black; line-height: 150%; font-family: 宋体">释放数据库连接，销毁连接池</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span><span style="color: black; line-height: 150%; font-family: 宋体">关闭与JMS的连接</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">}</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt; line-height: 150%; text-align: left" align="left"><span style="color: black; line-height: 150%; font-family: 宋体">在主线程中加入：Runtime.getRuntime().addShutdownHook(new Hook()) ;那么进程/线程会在退出的时候执行Hook的run方法，清理资源。</span></p>
<img src ="http://www.blogjava.net/jelver/aggbug/239470.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jelver/" target="_blank">冰河快狼</a> 2008-11-08 23:14 <a href="http://www.blogjava.net/jelver/articles/239470.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java.util.concurrent 多线程框架</title><link>http://www.blogjava.net/jelver/articles/238159.html</link><dc:creator>冰河快狼</dc:creator><author>冰河快狼</author><pubDate>Sun, 02 Nov 2008 04:00:00 GMT</pubDate><guid>http://www.blogjava.net/jelver/articles/238159.html</guid><wfw:comment>http://www.blogjava.net/jelver/comments/238159.html</wfw:comment><comments>http://www.blogjava.net/jelver/articles/238159.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jelver/comments/commentRss/238159.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jelver/services/trackbacks/238159.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 原文：http://www.ismayday.com/?p=170最近由于工作需要，回去好好复习了一遍java，学习和温习了和多线程，正则表达式，模式设计，Socket编程等相关的知识，基本算把某个相当牛的程序看懂了，从中收获颇深，近期也会把相关的知识点做成笔记放到博客来。当然在这里得好好感谢一下晟晟和刁，在我迷惑的时候问他们总能找到自己想要的答案，当然还有晟晟的书，《精通正则表达式》，看完之...&nbsp;&nbsp;<a href='http://www.blogjava.net/jelver/articles/238159.html'>阅读全文</a><img src ="http://www.blogjava.net/jelver/aggbug/238159.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jelver/" target="_blank">冰河快狼</a> 2008-11-02 12:00 <a href="http://www.blogjava.net/jelver/articles/238159.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>