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

见下面代码的:Thread.sleep(400000)部分,这里暂停线程模拟耗时操作后,别的客户端就连接不上了
[code="java"]
import java.io.IOException;

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.nio.ByteBuffer;

import java.nio.channels.ClosedChannelException;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

import java.util.Iterator;

/** 
 * @author marlonyao<yaolei135@gmail.com> 
 * 
 */  
public class EchoServer3 {  
    public static int DEFAULT_PORT = 9898;  

    interface Handler {  
        void execute(Selector selector, SelectionKey key);  
    }  


    public static void main(String[] args) throws IOException {  
        System.out.println("Listening for connection on port " + DEFAULT_PORT);  

        Selector selector = Selector.open();  
        initServer(selector);  

        while (true) {  
            selector.select();  

            for (Iterator<SelectionKey> itor = selector.selectedKeys().iterator(); itor.hasNext();) {  
                SelectionKey key = (SelectionKey) itor.next();  
                itor.remove();  
                Handler handler = (Handler) key.attachment();  
                handler.execute(selector, key);  
            }  
        }  
    }  

    private static void initServer(Selector selector) throws IOException,  
            ClosedChannelException {  
        ServerSocketChannel serverChannel = ServerSocketChannel.open();  
        ServerSocket ss = serverChannel.socket();  
        ss.bind(new InetSocketAddress(DEFAULT_PORT));  
        serverChannel.configureBlocking(false);  
        SelectionKey serverKey = serverChannel.register(selector, SelectionKey.OP_ACCEPT);  
        serverKey.attach(new ServerHandler());  
    }  

    static class ServerHandler implements Handler {  
        public void execute(Selector selector, SelectionKey key) {  
            ServerSocketChannel server = (ServerSocketChannel) key.channel();  
            SocketChannel client = null;  
            try {  
                client = server.accept();  
                System.out.println("Accepted connection from " + client);  
            } catch (IOException e) {  
                e.printStackTrace();  
                return;  
            }  

            SelectionKey clientKey = null;  
            try {  
                client.configureBlocking(false);  
                clientKey = client.register(selector, SelectionKey.OP_READ);  
                clientKey.attach(new ClientHandler());  
            } catch (IOException e) {  
                if (clientKey != null)  
                    clientKey.cancel();  
                try { client.close(); } catch (IOException ioe) { }  
            }  
        }  
    }  

    static class ClientHandler implements Handler {  
        private ByteBuffer buffer;  

        public ClientHandler() {  
            buffer = ByteBuffer.allocate(100);  
        }  

        public void execute(Selector selector, SelectionKey key) {  
            try {  
                if (key.isReadable()) {  
                    readKey(selector, key);  
                } else if (key.isWritable()) {  
                    writeKey(selector, key);  
                }  
            } catch (IOException e) {  
                key.cancel();  
                try { key.channel().close(); } catch (IOException ioe) { }  
            }  
        }  

        private void readKey(Selector selector, SelectionKey key) throws IOException {  
            SocketChannel client = (SocketChannel) key.channel();  
            try {  
                Thread.sleep(400000); 
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
            int n = client.read(buffer);  
            if (n > 0) {  
                buffer.flip();  
                key.interestOps(SelectionKey.OP_WRITE);     // switch to OP_WRITE  
            }  
        }  

        private void writeKey(Selector selector, SelectionKey key) throws IOException {  
            System.out.println("is writable...");  
            SocketChannel client = (SocketChannel) key.channel();  
            client.write(buffer);  
            if (buffer.remaining() == 0) {  // write finished, switch to OP_READ  
                buffer.clear();  
                key.interestOps(SelectionKey.OP_READ);  
            }  
        }  
    }  
}  

[/code]

2个回答

获取连接,分发处理,获取key这个是主线程,但是后续处理应该另起线程,handler应该是新起的线程处理,例如这样:
[code="java"]
while (true)
{
selector.select();
Set keys = selector.selectedKeys();
for (SelectionKey key : keys)
{
if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT)
{
ServerSocketChannel ss = (ServerSocketChannel) key
.channel();
SocketChannel sc = ss.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
keys.remove(key);
}
if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ)
{
SocketChannel cc = (SocketChannel) key.channel();
if (ReadThread.tag)
{
ReadThread readThread = new ReadThread();
readThread.setChannel(cc);
readThread.start();
keys.remove(key);
ReadThread.tag = false;
}
}

            }

        }

[/code]

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

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问