Java中的OIO和NIO详解(含代码)

news/2024/11/23 13:09:52/

简介及示例

Java NIO(New I/O)和OIO(Old I/O)是Java提供的两种不同的I/O模型。

OIO(Old I/O)是传统的阻塞I/O模型,也称为同步I/O。在OIO模型中,每个I/O操作(如读写操作)都会阻塞当前线程,直到操作完成或发生错误。当一个线程在执行一个I/O操作时,它无法进行其他任务,必须等待I/O操作完成后才能继续执行。这导致需要为每个连接创建一个独立的线程来处理I/O操作,当连接数量较多时,线程开销会很大。

相比之下,NIO(New I/O)是一种非阻塞I/O模型,也称为异步I/O。NIO模型中引入了选择器(Selector)和通道(Channel)的概念。通过Selector,一个线程可以同时监视多个通道的事件,并在事件发生时进行处理,从而实现了单线程处理多个通道的能力。NIO提供了一系列的Buffer,使得数据读写更加灵活。在NIO模型中,可以使用单个线程处理多个连接,大大减少了线程开销。

下面是一个简单的Java OIO(阻塞I/O)的代码示例:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;public class OIOExample {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8080);while (true) {Socket clientSocket = serverSocket.accept();BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);String message = in.readLine();System.out.println("Received message: " + message);out.println("Hello, Client!");in.close();out.close();clientSocket.close();}}
}

以上示例中,创建了一个ServerSocket并绑定到8080端口。通过accept()方法阻塞等待客户端连接,一旦有客户端连接进来,会创建一个新的Socket,并通过该Socket获取输入流和输出流。然后通过阻塞的方式进行读取和写入数据。

需要注意的是,在OIO模型中,每个连接都需要一个独立的线程来处理,当有大量的并发连接时,线程的创建和切换会带来较大的开销。

相比之下,NIO模型通过单线程处理多个通道的方式,减少了线程创建和切换的开销,提高了系统的并发能力。

下面是一个简单的Java NIO(非阻塞I/O)的代码示例:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;public class NIOExample {public static void main(String[] args) throws IOException {Selector selector = Selector.open();ServerSocketChannel serverChannel = ServerSocketChannel.open();serverChannel.socket().bind(new InetSocketAddress(8080));serverChannel.configureBlocking(false);serverChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {int readyChannels = selector.select();if (readyChannels == 0) {continue;}Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if (key.isAcceptable()) {ServerSocketChannel server = (ServerSocketChannel) key.channel();SocketChannel client = server.accept();client.configureBlocking(false);client.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {SocketChannel client = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = client.read(buffer);if (bytesRead > 0) {buffer.flip();byte[] data = new byte[bytesRead];buffer.get(data);String message = new String(data);System.out.println("Received message: " + message);} else if (bytesRead < 0) {client.close();}}keyIterator.remove();}}}
}

以上示例中,通过Selector来处理多个通道的读取事件。当有新的连接进来时,会将客户端SocketChannel注册到Selector上,监听读取事件(OP_READ),然后在循环中通过遍历selectedKeys来处理各个事件。

总结

区别:

  • 阻塞 vs 非阻塞:OIO是阻塞I/O模型,每个I/O操作都是阻塞的,即线程在执行I/O操作时会一直等待直到操作完成。NIO是非阻塞I/O模型,它使用Selector来实现非阻塞操作,允许单个线程处理多个通道的I/O事件。
  • 多线程 vs 单线程:OIO模型中,每个连接都需要创建一个独立的线程进行处理,当连接数量较多时,线程开销较大。NIO模型中,可以使用单个线程处理多个连接,减少了线程开销。
  • 通道和缓冲区:NIO引入了Channel和Buffer的概念,Channel用于读写数据,Buffer用于数据的存储和传输。OIO使用InputStream和OutputStream来进行数据的读写。

联系:

  • 都属于Java的I/O模型:无论是NIO还是OIO,都是Java提供的用于进行输入输出操作的模型。
  • 都可以实现网络编程:无论是NIO还是OIO,都可以用于实现网络编程,例如处理Socket连接、读写数据等。

总结来说,Java NIO相比于OIO提供了更高性能、更灵活的I/O操作方式,特别适用于处理大量连接的高并发场景。使用NIO可以充分利用单线程处理多个连接,减少线程开销。但是NIO的编程模型相对复杂,相比于OIO需要更多的代码和理解。选择使用哪种模型取决于具体的应用需求和场景。

如何选择

选择使用Java OIO(旧的I/O)还是Java NIO(新的I/O)取决于应用的需求和场景。以下是一些指导原则来帮助选择适合的I/O模型:

使用Java OIO(阻塞I/O)的情况:

  1. 简单性要求:如果你的应用相对简单,只需要处理少量的连接和数据,且对性能要求不高,使用OIO可以更容易编写和理解代码。
  2. 传统的阻塞模型:如果你习惯了传统的阻塞I/O编程模型,且代码已经使用了OIO,没有特别的性能需求,那么可以继续使用OIO。

使用Java NIO(非阻塞I/O)的情况:

  1. 高并发和大规模连接:如果你的应用需要处理大量的并发连接,例如高性能的服务器应用、网络游戏等,使用NIO可以更好地处理并发连接和提高吞吐量。
  2. 非阻塞操作:如果你需要在一个线程中处理多个通道的I/O操作,例如事件驱动编程、实现高性能的代理服务器等,使用NIO的Selector机制可以避免线程开销,提高效率。
  3. I/O操作与其他任务并发:如果你的应用需要将I/O操作与其他任务并发处理,例如同时处理网络I/O和计算任务,使用NIO可以更好地实现并发和资源的充分利用。

需要注意的是,NIO的编程模型相对复杂,相比于OIO需要更多的代码和理解。在使用NIO时,需要仔细考虑事件的处理逻辑和线程安全性。此外,NIO在某些场景下可能不如OIO稳定,例如处理低延迟和实时性要求较高的应用。

 


http://www.ppmy.cn/news/520840.html

相关文章

Python逻辑运算符及其用法

高中数学中我们就学过逻辑运算&#xff0c;例如 p 为真命题&#xff0c;q 为假命题&#xff0c;那么“p且q”为假&#xff0c;“p或q”为真&#xff0c;“非q”为真。Python也有类似的逻辑运算&#xff0c;请看下表&#xff1a; 表 1 Python 逻辑运算符及功能 逻辑运算符含义基…

Java 8新特性:方法引用的介绍与使用

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 1. 什么是方法引用&#xff1f; 2. 方法引用的…

端午day1作业

字符设备驱动对象结构体&#xff1a;struct cdev 字符设备驱动对象申请空间&#xff1a; &#xff08;1&#xff09;struct cdev cdev;//直接分配一个变量空间 &#xff08;2&#xff09;struct cdev *cdevcdev_alloc(); struct cdev *cdev_alloc(void);//手动申请字符设备驱…

Cookie,Session,Token,JWT授权方式对比

文章目录 HTTPCookieSessionSession认证流程Session 共享方案 TokenToken认证流程 JWTJWT认证流程 HTTP HTTP 本质上是无状态的&#xff0c;每个请求都是互相独立、毫无关联的&#xff0c;协议不要求客户端或服务器记录请求相关的信息。服务端无法确认当前访问者的身份信息&…

【Servlet学习一】认识Servlet 创建第一个Servlet项目

目录 &#x1f31f;需要知道&#xff1a; &#x1f308;1、Tomcat是什么&#xff1f; &#x1f308; 2、Maven &#x1f31f;一、认识Servlet &#x1f308;1、Servlet是什么&#xff1f; &#x1f308;2、实现第一个Servlet项目。 &#x1f308;3、简单了解Postman工具…

【计组】微指令 微操作 微命令 微程序

区分四个概念 &#xff08;1&#xff09;微命令:微命令是构成控制信号序列的最小单位。通常是指那些直接作用于部件或控制门电路的控制命令。 &#xff08;2&#xff09;微操作:由微命令控制实现的最基本的操作称为微操作。 &#xff08;3&#xff09;微指令:以产生一组微命令&…

怎么将存入此电脑中的图片放入电脑D盘

先找到图片的目录&#xff0c; 目录为&#xff1a;xxx 然后 现在图片目录就移动到D盘了

CGB2103-day01

1.SpringMVC 1.1 框架的作用 接收前端传递的数据,与用户进行交互. 1.2 SpringMVC参数传递的格式 1.2.1 简单参数传值 <input type"text" name"username" value"admin" /><input type"text" name"age" …