0 0

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

见下面代码的:Thread.sleep(400000)部分,这里暂停线程模拟耗时操作后,别的客户端就连接不上了
    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);  
                }  
            }  
        }  
    }  

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


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

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

0 0

采纳的答案

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

 while (true)
            {
                selector.select();
                Set<SelectionKey> 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;
                        }
                    }

                }

            }

2012年3月12日 17:42
0 0

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

2012年3月12日 17:40

相关推荐

    Nio多线程CS收发信息问题(问题已经解决)

    在NIO中,服务端通常创建一个主线程负责选择和调度事件,然后根据需要创建工作线程来处理具体任务,这样可以避免主线程被某个耗时操作阻塞。 描述中提到了"本工程源码",这通常意味着可以通过查看和分析代码来理解...

    新输入输出NIO

    NIO还引入了**选择器(Selectors)**,允许单线程管理多个通道,从而实现多路复用I/O。选择器通过注册感兴趣的通道并在事件发生时通知应用程序,从而提高了系统的并发性。 **异步I/O(Asynchronous I/O)**是NIO的...

    java nio 原理浅析

    - **单Reactor单线程模型**:所有工作包括接受新连接、处理I/O事件和调用处理器都在同一个线程中进行,适用于简单且快速处理的任务。 - **主从Reactor多线程模型**:分为主反应器和从反应器,主反应器负责接受新...

    Java通信项目之客户端UI实现以及交互

    - 考虑使用SwingWorker或JavaFX的Task类,它们允许在后台执行耗时操作并更新UI。 5. **数据持久化**: - 可能需要保存聊天记录,可以使用文件系统、数据库或者云存储。SQLite是一个轻量级的数据库,适合本地数据...

    android 线程间通讯

    - 一个单线程的、有序执行任务的服务,适合处理耗时操作且不需要长时间保持服务状态的场景。 - 当工作队列中的任务执行完毕后,IntentService会自动停止自身。 5. **HandlerThread**: - 专门用于创建一个新的...

    Network-programming:服务端和客户端,无线程和多线程

    在单线程模型中,程序只有一个执行流,这意味着同一时间只能执行一个任务。然而,对于需要处理多个并发请求的服务端来说,单线程效率较低。这就引出了多线程的概念。Java提供了丰富的多线程支持,包括`Thread`类和`...

    Java NIO工作原理的全面分析

    NIO将I/O操作中最耗时的部分——数据的填充和提取——交由操作系统处理,从而提升了速度。此外,NIO支持非阻塞I/O,允许一个线程处理多个通道,提高了并发处理能力。 **通道与缓冲区** 1. **通道(Channel)**:...

    Android多线程断点下载.rar

    在传统的单线程下载中,文件数据流通过一个连接进行传输,如果网络不稳定或者速度慢,整个下载过程可能会非常耗时。多线程下载则是将文件分成多个部分,每个部分由一个单独的线程负责下载,这样可以充分利用网络...

    Android多线程断点续传下载器

    由于Android主线程不支持耗时操作,我们需使用`Handler`或`LiveData`等机制,在后台线程计算进度,并在主线程中更新UI。 8. **异常处理**: 在下载过程中可能出现网络错误、文件存储问题等异常情况,因此需要捕获...

    Android多线程下载项目.zip

    在Android开发中,多线程下载是一项常见的任务,它能够提高下载速度,改善用户体验,特别是在处理大文件或者网络条件不稳定的场景下。本项目“Android多线程下载”旨在实现一个高效、可靠的文件下载功能,利用多线程...

    java点对点聊天(非阻塞式网络编程)

    4. **多线程和并发**:虽然非阻塞I/O允许单线程处理多个连接,但在某些情况下,如处理复杂的业务逻辑或执行耗时操作时,可能需要使用多线程。Java的ExecutorService可以帮助我们管理和调度这些线程。 5. **安全性**...

    gRPC线程模型分析

    Netty是一个基于NIO的高性能网络通信框架,常用于gRPC实现中,其线程模型(Reactor模式)分为两种:单线程Reactor和多线程Reactor。 - **单线程Reactor**:一个线程处理所有I/O事件,适合小规模服务,但可能会...

    java网络编程(非阻塞与阻塞编程)

    这种模式下,如果I/O操作耗时较长,将严重影响程序的响应速度和效率。而非阻塞编程则试图解决这一问题,它允许程序在等待I/O操作时,可以继续执行其他任务,提高程序的并发处理能力。 ### Java网络编程中的阻塞模式...

    Java实现多线程下载源代码

    在Java编程领域,多线程技术是不可或缺的一部分,特别是在处理耗时操作,如大文件下载时,多线程能够显著提升程序的效率和用户体验。本文将深入探讨如何使用Java实现多线程下载,并通过"Java实现多线程下载源代码"这...

    thrift阻塞与非阻塞模式下的测试

    Thrift是一种高效的、跨语言的服务框架,由Facebook开发并开源,主要用于构建分布式...在实际应用中,可能需要结合具体情况,选择单线程阻塞、多线程阻塞、异步IO、NIO或AIO等模式的组合,以达到最优的性能和资源利用。

    tomcat中多线程对于servlet处理的4篇资料

    然而,如果Servlet在处理请求时执行了耗时操作(如数据库查询或IO操作),这可能会阻塞线程,影响其他请求的处理。 4. **线程池的优化** 调整线程池的大小是一项重要的优化策略。过大可能导致内存资源浪费,过小...

    基于java AIO实现的RPC调用框架.zip

    Java AIO,全称为Asynchronous Input/Output,是Java NIO的一个扩展,它提供了一种异步非阻塞的I/O操作方式,特别是在处理高并发、低延迟的网络通信场景时,AIO具有显著的优势。在RPC(Remote Procedure Call)框架...

    Android实例:多线程文件下载+在线音乐播放+清除下载文件

    在Android中,由于主线程(UI线程)不能执行耗时操作,因此在进行大文件下载时,我们需要使用多线程技术。通常,我们会创建一个后台线程来处理网络请求和文件写入,以避免阻塞UI。使用`AsyncTask`或`IntentService`...

    updateDemo

    在单线程下载中,文件数据从服务器到客户端是连续传输的,如果网络不稳定或者速度慢,下载过程可能会非常耗时。多线程下载则将文件分割成多个部分,每个部分在不同的线程中并行下载,从而提高了下载速度。这通常通过...

    Socket通信工具小案例,使用异步处理数据

    在高并发环境下,单线程可能会成为性能瓶颈,因为它一次只能处理一个请求。而多线程则可以让服务器同时处理多个客户端的请求,提升服务的响应速度。每个线程独立处理一个Socket连接,这样可以避免等待一个耗时操作...

Global site tag (gtag.js) - Google Analytics