请解释 Java 中的 IO 和 NIO 的区别,以及 NIO 如何实现多路复用?

Java中的IO和NIO是两种不同的输入输出处理方式,它们在设计理念、实现方式、性能特点和应用场景上有着显著的差异。

下面我将详细解释Java中的IO和NIO的区别,以及NIO如何实现多路复用,并提供一些日常开发中的使用建议和注意事项。

Java中的IO和NIO的区别

1. 面向流与面向缓冲
  • Java IO:面向流的处理方式,基于传统的阻塞式输入输出模型。数据以顺序的方式流动,且在读写过程中,一般情况下会阻塞当前线程,直到操作完成。

    // Java IO示例:读取文件内容
    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;public class FileIOExample {public static void main(String[] args) {String filePath = "example.txt";try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {String line;while ((line = br.readLine()) != null) {System.out.println(line);}} catch (IOException e) {e.printStackTrace();}}
    }
  • Java NIO:面向缓冲区的处理方式,数据读取到一个缓冲区,需要时可在缓冲区中前后移动。这增加了处理过程中的灵活性。

    // Java NIO示例:读取文件内容
    import java.nio.file.Files;
    import java.nio.file.Paths;
    import java.io.IOException;public class FileNIOExample {public static void main(String[] args) {String filePath = "example.txt";try {Files.lines(Paths.get(filePath)).forEach(System.out::println);} catch (IOException e) {e.printStackTrace();}}
    }
2. 阻塞与非阻塞IO
  • Java IO:各种流是阻塞的,当一个线程调用read()或write()时,该线程被阻塞,直到数据传输完成。

    // Java IO示例:阻塞式读取数据
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;public class BlockingIOExample {public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("example.txt")) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = inputStream.read(buffer)) != -1) {System.out.write(buffer, 0, bytesRead);}} catch (IOException e) {e.printStackTrace();}}
    }
  • Java NIO:支持非阻塞模式,当一个通道没有数据可读时,线程可以继续处理其他事情,而不是阻塞在原地等待。

    // Java NIO示例:非阻塞式读取数据
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.nio.file.StandardOpenOption;
    import java.io.IOException;public class NonBlockingNIOExample {public static void main(String[] args) {Path path = Paths.get("example.txt");try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ)) {ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead;while ((bytesRead = fileChannel.read(buffer)) != -1) {buffer.flip();while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}buffer.clear();}} catch (IOException e) {e.printStackTrace();}}
    }
3. 选择器(Selectors)
  • Java IO:没有选择器的概念,每个连接需要独立的线程进行处理。
  • Java NIO:通过Selector实现单线程管理多个Channel,通过select调用,可以获取已经准备好的Channel并进行相应的处理。
    // Java NIO示例:使用Selector实现多路复用
    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;public class NIOServer {public static void main(String[] args) throws IOException {Selector selector = Selector.open();ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8080));serverSocketChannel.configureBlocking(false);serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {int readyChannels = selector.select();if (readyChannels == 0) continue;Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if (key.isAcceptable()) {ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();SocketChannel clientChannel = serverChannel.accept();clientChannel.configureBlocking(false);clientChannel.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {SocketChannel clientChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = clientChannel.read(buffer);if (bytesRead > 0) {buffer.flip();while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}buffer.clear();}}keyIterator.remove();}}}
    }

NIO如何实现多路复用

NIO通过Selector实现多路复用,Selector允许一个线程同时监控多个Channel。当一个Channel有事件发生时,Selector会通知相应的线程进行处理。这就大大减少了线程的开销,让系统能够在高并发场景下保持高效。

Selector的工作原理
  1. 注册事件:应用程序将多个Channel注册到Selector上,通常注册的是感兴趣的事件,比如读(OP_READ)、写(OP_WRITE)等。
  2. 事件等待:在应用程序调用selector.select()方法时,Selector会阻塞,直到有通道准备好进行某种操作。此时,它会检查是否有通道处于就绪状态。
  3. 事件分发:一旦某个Channel准备好操作,Selector会返回一个包含所有就绪事件的集合。应用程序可以遍历这个集合,针对每个就绪的Channel执行相应的读写操作。
  4. 事件处理:处理完相关的事件后,应用程序可以选择继续等待,或者再次注册其他事件。
示例代码
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;public class NIOServer {public static void main(String[] args) throws IOException {Selector selector = Selector.open();ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8080));serverSocketChannel.configureBlocking(false);serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {int readyChannels = selector.select();if (readyChannels == 0) continue;Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if (key.isAcceptable()) {ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();SocketChannel clientChannel = serverChannel.accept();clientChannel.configureBlocking(false);clientChannel.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {SocketChannel clientChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = clientChannel.read(buffer);if (bytesRead > 0) {buffer.flip();while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}buffer.clear();}}keyIterator.remove();}}}
}

日常开发中的使用建议和注意事项

  1. 选择合适的IO模型

    • 对于简单的数据交互,如文件读写、小规模网络通信等,可以使用传统的IO。
    • 对于高并发、需要高性能的场景,如服务器开发、大数据处理等,建议使用NIO。
  2. 合理使用缓冲区

    • 在NIO中,缓冲区(Buffer)是数据读写的核心。合理使用缓冲区可以提高数据处理的效率。
    • 注意缓冲区的状态管理,如flip、clear、compact等操作,确保数据正确读写。
  3. 处理异常和资源释放

    • 在IO操作中,务必处理IOException,确保程序的健壮性。
    • 使用try-with-resources语句或finally块确保资源正确释放,避免内存泄漏。
  4. 避免过度优化

    • 在选择IO模型时,不要过度优化。对于简单的任务,使用传统的IO可能更加方便和高效。
    • 只有在确实需要高性能时,才考虑使用NIO或NIO 2。

通过理解Java中的IO和NIO的区别,以及NIO如何实现多路复用,开发者可以根据具体需求选择合适的IO模型,从而提高程序的性能和效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/12517.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法题(57):找出字符串中第一个匹配项的下标

审题: 需要我们根据原串与模式串相比较并找到完全匹配时子串的第一个元素索引&#xff0c;若没有则返回-1 思路&#xff1a; 方法一&#xff1a;BF暴力算法 思路很简单&#xff0c;我们用p1表示原串的索引&#xff0c;p2表示模式串索引。遍历原串&#xff0c;每次遍历都匹配一次…

「全网最细 + 实战源码案例」设计模式——策略模式

核心思想 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;用于定义一系列算法或策略&#xff0c;将它们封装成独立的类&#xff0c;并使它们可以相互替换&#xff0c;而不影响客户端的代码&#xff0c;提高代码的可维护性和扩展性。 结构 …

linux 进程补充

环境变量 基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如&#xff1a;我们在编写C/C代码的时候&#xff0c;在链接的时候&#xff0c;从来不知道我们的所链接的动态静态库在哪 里&#xff0c;但是照样可以链接成功&#…

排序算法--选择排序

选择排序虽然简单&#xff0c;但时间复杂度较高&#xff0c;适合小规模数据或教学演示。 // 选择排序函数 void selectionSort(int arr[], int n) {for (int i 0; i < n - 1; i) { // 外层循环控制当前最小值的存放位置int minIndex i; // 假设当前位置是最小值的索引// 内…

java求职学习day27

数据库连接池 &DBUtils 1.数据库连接池 1.1 连接池介绍 1) 什么是连接池 实际开发中 “ 获得连接 ” 或 “ 释放资源 ” 是非常消耗系统资源的两个过程&#xff0c;为了解决此类性能问题&#xff0c;通常情况我们 采用连接池技术&#xff0c;来共享连接 Connection 。…

接入DeepSeek大模型

接入DeepSeek 下载并安装Ollamachatbox 软件配置大模型 下载并安装Ollama 下载并安装Ollama&#xff0c; 使用参数ollama -v查看是否安装成功。 输入命令ollama list&#xff0c; 可以看到已经存在4个目录了。 输入命令ollama pull deepseek-r1:1.5b&#xff0c; 下载deepse…

AI大模型(二)基于Deepseek搭建本地可视化交互UI

AI大模型&#xff08;二&#xff09;基于Deepseek搭建本地可视化交互UI DeepSeek开源大模型在榜单上以黑马之姿横扫多项评测&#xff0c;其社区热度指数暴涨、一跃成为近期内影响力最高的话题&#xff0c;这个来自中国团队的模型向世界证明&#xff1a;让每个普通人都能拥有媲…

防火墙安全策略实验

一、实验拓扑图及实验要求 实验要求&#xff1a; 1、VLAN2属于办公区&#xff1b;VLAN 3属于生产区。 2、办公区PC在工作日时间&#xff08;周一至周五&#xff0c;早8到晚6)可以正常访问0A Server&#xff0c;其他时间不允许。 3、办公区可以在任意时刻访问web Server 4、生产…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】3.1 NumPy图像大小调整实战

3.1 NumPy图像大小调整实战 目录 #mermaid-svg-uDg4hyooC74c0r2r {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-uDg4hyooC74c0r2r .error-icon{fill:#552222;}#mermaid-svg-uDg4hyooC74c0r2r .error-text{fill:#5…

AI 编程工具—Cursor进阶使用 Agent模式

AI 编程工具—Cursor进阶使用 Agent模式 我们在使用Cursor 的是有,在Composer 模式下,提交的是有两种模式 Normal 模式,也就是默认的模式Agent 模式Agent 模式可以帮我们生成代码文件,执行程序,安装依赖,并且完成一些列的工作 这里有个点很重要就是在Agent 模式下,Cur…

在React中使用redux

一、首先安装两个插件 1.Redux Toolkit 2.react-redux 第一步&#xff1a;创建模块counterStore 第二步&#xff1a;在store的入口文件进行子模块的导入组合 第三步&#xff1a;在index.js中进行store的全局注入 第四步&#xff1a;在组件中进行使用 第五步&#xff1a;在组件中…

Leetcode - 周赛434

目录 一、3432. 统计元素和差值为偶数的分区方案二、3433. 统计用户被提及情况三、3434. 子数组操作后的最大频率四、3435. 最短公共超序列的字母出现频率 一、3432. 统计元素和差值为偶数的分区方案 题目链接 本题可以直接模拟&#xff0c;这里再介绍一个数学做法&#xff0…

Linux: 网络基础

1.协议 为什么要有协议&#xff1a;减少通信成本。所有的网络问题&#xff0c;本质是传输距离变长了。 什么是协议&#xff1a;用计算机语言表达的约定。 2.分层 软件设计方面的优势—低耦合。 一般我们的分层依据&#xff1a;功能比较集中&#xff0c;耦合度比较高的模块层…

Spring Boot常用注解深度解析:从入门到精通

今天&#xff0c;这篇文章带你将深入理解Spring Boot中30常用注解&#xff0c;通过代码示例和关系图&#xff0c;帮助你彻底掌握Spring核心注解的使用场景和内在联系。 一、启动类与核心注解 1.1 SpringBootApplication 组合注解&#xff1a; SpringBootApplication Confi…

【大模型理论篇】DeepSeek-R1:引入冷启动的强化学习

1. 背景 首先给出DeepSeek-V3、DeepSeek-R1-Zero、DeepSeek-R1的关系图【1】。 虽然DeepSeek-R1-Zero推理能力很强&#xff0c;但它也面临一些问题。例如&#xff0c;DeepSeek-R1-Zero存在可读性差和语言混杂等问题。为了使推理过程更具可读性&#xff0c;进而推出了DeepSee…

【BUUCTF杂项题】荷兰宽带数据泄露、九连环

一.荷兰宽带数据泄露 打开发现是一个.bin为后缀的二进制文件&#xff0c;因为提示宽带数据泄露&#xff0c;考虑是宽带路由器方向的隐写 补充&#xff1a;大多数现代路由器都可以让您备份一个文件路由器的配置文件&#xff0c;软件RouterPassView可以读取这个路由配置文件。 用…

院校联合以项目驱动联合培养医工计算机AI人才路径探析

一、引言 1.1 研究背景与意义 在科技飞速发展的当下&#xff0c;医疗人工智能作为一个极具潜力的新兴领域&#xff0c;正深刻地改变着传统医疗模式。从疾病的早期诊断、个性化治疗方案的制定&#xff0c;到药物研发的加速&#xff0c;人工智能技术的应用极大地提升了医疗服务…

解读“大语言模型(LLM)安全性测评基准”

1. 引入 OWASP&#xff0c;全称为Open Web Application Security Project&#xff0c;即开放式Web应用程序安全项目&#xff0c;是一个致力于提高软件安全性的非营利国际组织。 由于庞大的规模和复杂的结构&#xff0c;大语言模型也存在多种安全风险&#xff0c;如prompt误导…

【大数据技术】教程03:本机PyCharm远程连接虚拟机Python

本机PyCharm远程连接虚拟机Python 注意:本文需要使用PyCharm专业版。 pycharm-professional-2024.1.4VMware Workstation Pro 16CentOS-Stream-10-latest-x86_64-dvd1.iso写在前面 本文主要介绍如何使用本地PyCharm远程连接虚拟机,运行Python脚本,提高编程效率。 注意: …

Notepad++消除生成bak文件

设置(T) ⇒ 首选项... ⇒ 备份 ⇒ 勾选 "禁用" 勾选禁用 就不会再生成bak文件了 notepad怎么修改字符集编码格式为gbk 如图所示