关于NIO的疑问,NIO是单线程的,如果后台有比较耗时的操作,别的客户端不就连不进来了?

见下面代码的:Thread.sleep(400000)部分,这里暂停线程模拟耗时操作后,别的客户端就连接不上了 
Java代码   收藏代码
  1. import java.io.IOException;    
  2. import java.net.InetSocketAddress;    
  3. import java.net.ServerSocket;    
  4. import java.nio.ByteBuffer;    
  5. import java.nio.channels.ClosedChannelException;    
  6. import java.nio.channels.SelectionKey;    
  7. import java.nio.channels.Selector;    
  8. import java.nio.channels.ServerSocketChannel;    
  9. import java.nio.channels.SocketChannel;    
  10. import java.util.Iterator;    
  11.     
  12.     
  13. /**  
  14.  * @author marlonyao<yaolei135@gmail.com>  
  15.  *  
  16.  */    
  17. public class EchoServer3 {    
  18.     public static int DEFAULT_PORT = 9898;    
  19.     
  20.     interface Handler {    
  21.         void execute(Selector selector, SelectionKey key);    
  22.     }    
  23.     
  24.         
  25.     public static void main(String[] args) throws IOException {    
  26.         System.out.println("Listening for connection on port " + DEFAULT_PORT);    
  27.     
  28.         Selector selector = Selector.open();    
  29.         initServer(selector);    
  30.     
  31.         while (true) {    
  32.             selector.select();    
  33.     
  34.             for (Iterator<SelectionKey> itor = selector.selectedKeys().iterator(); itor.hasNext();) {    
  35.                 SelectionKey key = (SelectionKey) itor.next();    
  36.                 itor.remove();    
  37.                 Handler handler = (Handler) key.attachment();    
  38.                 handler.execute(selector, key);    
  39.             }    
  40.         }    
  41.     }    
  42.     
  43.     private static void initServer(Selector selector) throws IOException,    
  44.             ClosedChannelException {    
  45.         ServerSocketChannel serverChannel = ServerSocketChannel.open();    
  46.         ServerSocket ss = serverChannel.socket();    
  47.         ss.bind(new InetSocketAddress(DEFAULT_PORT));    
  48.         serverChannel.configureBlocking(false);    
  49.         SelectionKey serverKey = serverChannel.register(selector, SelectionKey.OP_ACCEPT);    
  50.         serverKey.attach(new ServerHandler());    
  51.     }    
  52.         
  53.     static class ServerHandler implements Handler {    
  54.         public void execute(Selector selector, SelectionKey key) {    
  55.             ServerSocketChannel server = (ServerSocketChannel) key.channel();    
  56.             SocketChannel client = null;    
  57.             try {    
  58.                 client = server.accept();    
  59.                 System.out.println("Accepted connection from " + client);    
  60.             } catch (IOException e) {    
  61.                 e.printStackTrace();    
  62.                 return;    
  63.             }    
  64.                 
  65.             SelectionKey clientKey = null;    
  66.             try {    
  67.                 client.configureBlocking(false);    
  68.                 clientKey = client.register(selector, SelectionKey.OP_READ);    
  69.                 clientKey.attach(new ClientHandler());    
  70.             } catch (IOException e) {    
  71.                 if (clientKey != null)    
  72.                     clientKey.cancel();    
  73.                 try { client.close(); } catch (IOException ioe) { }    
  74.             }    
  75.         }    
  76.     }    
  77.         
  78.     static class ClientHandler implements Handler {    
  79.         private ByteBuffer buffer;    
  80.             
  81.         public ClientHandler() {    
  82.             buffer = ByteBuffer.allocate(100);    
  83.         }    
  84.             
  85.         public void execute(Selector selector, SelectionKey key) {    
  86.             try {    
  87.                 if (key.isReadable()) {    
  88.                     readKey(selector, key);    
  89.                 } else if (key.isWritable()) {    
  90.                     writeKey(selector, key);    
  91.                 }    
  92.             } catch (IOException e) {    
  93.                 key.cancel();    
  94.                 try { key.channel().close(); } catch (IOException ioe) { }    
  95.             }    
  96.         }    
  97.             
  98.         private void readKey(Selector selector, SelectionKey key) throws IOException {    
  99.             SocketChannel client = (SocketChannel) key.channel();    
  100.             try {    
  101.                 Thread.sleep(400000);   
  102.             } catch (InterruptedException e) {    
  103.                 // TODO Auto-generated catch block    
  104.                 e.printStackTrace();    
  105.             }    
  106.             int n = client.read(buffer);    
  107.             if (n > 0) {    
  108.                 buffer.flip();    
  109.                 key.interestOps(SelectionKey.OP_WRITE);     // switch to OP_WRITE    
  110.             }    
  111.         }    
  112.             
  113.         private void writeKey(Selector selector, SelectionKey key) throws IOException {    
  114.             System.out.println("is writable...");    
  115.             SocketChannel client = (SocketChannel) key.channel();    
  116.             client.write(buffer);    
  117.             if (buffer.remaining() == 0) {  // write finished, switch to OP_READ    
  118.                 buffer.clear();    
  119.                 key.interestOps(SelectionKey.OP_READ);    
  120.             }    
  121.         }    
  122.     }    
  123. }    

问题补充:
wangqj 写道
好比去肯德基吃饭,前台只有一个点餐员,如果客人要的餐简单,能快速的完成点餐(相当于IO处理),然后让客人等厨师做好饭(相当于后台业务处理),然后通知客人取餐。 这个时候能快速接受排队的客人的请求。  如果某个客人要了很多吃的,点餐的时间就比较长,后面排队的客人就要等,这时效率就低了


那这样的话业务逻辑处理部分(厨师做饭)就必须用线程(池)来做了,没办法
2012年3月12日 17:06

2个答案按时间排序按投票排序

0 0

采纳的答案

获取连接,分发处理,获取key这个是主线程,但是后续处理应该另起线程,handler应该是新起的线程处理,例如这样: 

Java代码   收藏代码
  1. while (true)  
  2.            {  
  3.                selector.select();  
  4.                Set<SelectionKey> keys = selector.selectedKeys();  
  5.                for (SelectionKey key : keys)  
  6.                {  
  7.                    if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT)  
  8.                    {  
  9.                        ServerSocketChannel ss = (ServerSocketChannel) key  
  10.                                .channel();  
  11.                        SocketChannel sc = ss.accept();  
  12.                        sc.configureBlocking(false);  
  13.                        sc.register(selector, SelectionKey.OP_READ);  
  14.                        keys.remove(key);  
  15.                    }  
  16.                    if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ)  
  17.                    {  
  18.                        SocketChannel cc = (SocketChannel) key.channel();  
  19.                        if (ReadThread.tag)  
  20.                        {  
  21.                            ReadThread readThread = new ReadThread();  
  22.                            readThread.setChannel(cc);  
  23.                            readThread.start();  
  24.                            keys.remove(key);  
  25.                            ReadThread.tag = false;  
  26.                        }  
  27.                    }  
  28.   
  29.                }  
  30.   
  31.            }  

2012年3月12日 17:42
0 0

好比去肯德基吃饭,前台只有一个点餐员,如果客人要的餐简单,能快速的完成点餐(相当于IO处理),然后让客人等厨师做好饭(相当于后台业务处理),然后通知客人取餐。 这个时候能快速接受排队的客人的请求。  如果某个客人要了很多吃的,点餐的时间就比较长,后面排队的客人就要等,这时效率就低了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值