-
关于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个答案 按时间排序 按投票排序
-
采纳的答案
获取连接,分发处理,获取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
-
好比去肯德基吃饭,前台只有一个点餐员,如果客人要的餐简单,能快速的完成点餐(相当于IO处理),然后让客人等厨师做好饭(相当于后台业务处理),然后通知客人取餐。 这个时候能快速接受排队的客人的请求。 如果某个客人要了很多吃的,点餐的时间就比较长,后面排队的客人就要等,这时效率就低了
2012年3月12日 17:40
相关推荐
在NIO中,服务端通常创建一个主线程负责选择和调度事件,然后根据需要创建工作线程来处理具体任务,这样可以避免主线程被某个耗时操作阻塞。 描述中提到了"本工程源码",这通常意味着可以通过查看和分析代码来理解...
NIO还引入了**选择器(Selectors)**,允许单线程管理多个通道,从而实现多路复用I/O。选择器通过注册感兴趣的通道并在事件发生时通知应用程序,从而提高了系统的并发性。 **异步I/O(Asynchronous I/O)**是NIO的...
- **单Reactor单线程模型**:所有工作包括接受新连接、处理I/O事件和调用处理器都在同一个线程中进行,适用于简单且快速处理的任务。 - **主从Reactor多线程模型**:分为主反应器和从反应器,主反应器负责接受新...
- 考虑使用SwingWorker或JavaFX的Task类,它们允许在后台执行耗时操作并更新UI。 5. **数据持久化**: - 可能需要保存聊天记录,可以使用文件系统、数据库或者云存储。SQLite是一个轻量级的数据库,适合本地数据...
- 一个单线程的、有序执行任务的服务,适合处理耗时操作且不需要长时间保持服务状态的场景。 - 当工作队列中的任务执行完毕后,IntentService会自动停止自身。 5. **HandlerThread**: - 专门用于创建一个新的...
在单线程模型中,程序只有一个执行流,这意味着同一时间只能执行一个任务。然而,对于需要处理多个并发请求的服务端来说,单线程效率较低。这就引出了多线程的概念。Java提供了丰富的多线程支持,包括`Thread`类和`...
NIO将I/O操作中最耗时的部分——数据的填充和提取——交由操作系统处理,从而提升了速度。此外,NIO支持非阻塞I/O,允许一个线程处理多个通道,提高了并发处理能力。 **通道与缓冲区** 1. **通道(Channel)**:...
在传统的单线程下载中,文件数据流通过一个连接进行传输,如果网络不稳定或者速度慢,整个下载过程可能会非常耗时。多线程下载则是将文件分成多个部分,每个部分由一个单独的线程负责下载,这样可以充分利用网络...
由于Android主线程不支持耗时操作,我们需使用`Handler`或`LiveData`等机制,在后台线程计算进度,并在主线程中更新UI。 8. **异常处理**: 在下载过程中可能出现网络错误、文件存储问题等异常情况,因此需要捕获...
在Android开发中,多线程下载是一项常见的任务,它能够提高下载速度,改善用户体验,特别是在处理大文件或者网络条件不稳定的场景下。本项目“Android多线程下载”旨在实现一个高效、可靠的文件下载功能,利用多线程...
4. **多线程和并发**:虽然非阻塞I/O允许单线程处理多个连接,但在某些情况下,如处理复杂的业务逻辑或执行耗时操作时,可能需要使用多线程。Java的ExecutorService可以帮助我们管理和调度这些线程。 5. **安全性**...
Netty是一个基于NIO的高性能网络通信框架,常用于gRPC实现中,其线程模型(Reactor模式)分为两种:单线程Reactor和多线程Reactor。 - **单线程Reactor**:一个线程处理所有I/O事件,适合小规模服务,但可能会...
这种模式下,如果I/O操作耗时较长,将严重影响程序的响应速度和效率。而非阻塞编程则试图解决这一问题,它允许程序在等待I/O操作时,可以继续执行其他任务,提高程序的并发处理能力。 ### Java网络编程中的阻塞模式...
在Java编程领域,多线程技术是不可或缺的一部分,特别是在处理耗时操作,如大文件下载时,多线程能够显著提升程序的效率和用户体验。本文将深入探讨如何使用Java实现多线程下载,并通过"Java实现多线程下载源代码"这...
Thrift是一种高效的、跨语言的服务框架,由Facebook开发并开源,主要用于构建分布式...在实际应用中,可能需要结合具体情况,选择单线程阻塞、多线程阻塞、异步IO、NIO或AIO等模式的组合,以达到最优的性能和资源利用。
然而,如果Servlet在处理请求时执行了耗时操作(如数据库查询或IO操作),这可能会阻塞线程,影响其他请求的处理。 4. **线程池的优化** 调整线程池的大小是一项重要的优化策略。过大可能导致内存资源浪费,过小...
Java AIO,全称为Asynchronous Input/Output,是Java NIO的一个扩展,它提供了一种异步非阻塞的I/O操作方式,特别是在处理高并发、低延迟的网络通信场景时,AIO具有显著的优势。在RPC(Remote Procedure Call)框架...
在Android中,由于主线程(UI线程)不能执行耗时操作,因此在进行大文件下载时,我们需要使用多线程技术。通常,我们会创建一个后台线程来处理网络请求和文件写入,以避免阻塞UI。使用`AsyncTask`或`IntentService`...
在单线程下载中,文件数据从服务器到客户端是连续传输的,如果网络不稳定或者速度慢,下载过程可能会非常耗时。多线程下载则将文件分割成多个部分,每个部分在不同的线程中并行下载,从而提高了下载速度。这通常通过...
在高并发环境下,单线程可能会成为性能瓶颈,因为它一次只能处理一个请求。而多线程则可以让服务器同时处理多个客户端的请求,提升服务的响应速度。每个线程独立处理一个Socket连接,这样可以避免等待一个耗时操作...