Java的NIO

在这里插入图片描述

Java NIO(New I/O,新 I/O)是 Java 1.4 版本引入的一组用于进行非阻塞 I/O 操作的 API。相比于传统的 Java I/O(或称为 IOStream),Java NIO 提供了更为灵活、可扩展和高性能的 I/O 处理方式。

Java NIO 的核心组件主要包括以下几个部分:

  1. 通道(Channel)和缓冲区(Buffer)

    • 通道代表了连接到实体(如文件、网络套接字等)的打开连接。通道可以进行读取和写入操作。
    • 缓冲区是一个对象,它存储了数据,用于在通道之间传输。通常是通过字节缓冲区(ByteBuffer)、字符缓冲区(CharBuffer)、整数缓冲区(IntBuffer)等来操作数据。
  2. 选择器(Selector)

    • 选择器是 Java NIO 实现非阻塞 I/O 的关键部分。它允许单个线程处理多个通道的 I/O 操作。通过选择器,可以实现一个线程管理多个通道的能力,提高了处理连接的效率。
  3. 通道和选择器的配合使用

    • 通过将通道注册到选择器中,可以让一个选择器监视多个通道上的事件。当一个或多个通道上的事件发生时(比如数据准备就绪、连接就绪等),选择器会通知程序,程序可以处理这些事件。

Java NIO 提供了更底层、更灵活的 API,使得开发者可以更好地控制 I/O 操作,并在处理大量连接时获得更好的性能。它通常用于构建需要高性能网络通信的应用程序,如网络服务器、实时通信系统等。

虽然 Java NIO 提供了更多的控制权和性能优势,但它也更为复杂,相较于传统的 Java I/O,使用起来可能需要更多的编程经验和理解。近年来,一些高级框架(如 Netty、Vert.x 等)基于 Java NIO,使得开发者更容易使用和管理非阻塞 I/O,减少了开发的复杂性。

1.为什么会出现NIO

Java NIO(New I/O)的出现是为了解决传统 I/O 在处理大量连接时的性能问题。在传统的阻塞 I/O 模型中,每个连接都需要一个单独的线程来处理,当连接数量增多时,会导致线程数量暴增,消耗大量系统资源,且效率低下。

Java NIO 的出现主要是为了解决传统 I/O 的几个问题:

  1. 连接数量与线程开销问题:传统 I/O 模型中,每个连接需要一个独立的线程来处理,线程开销较大。当连接数目增多时,会消耗过多的系统资源,同时线程切换开销也会增加。

  2. 阻塞与非阻塞:传统 I/O 操作是阻塞的,即当数据准备好之前,线程会一直等待数据的到来。在某些场景下,这种等待会导致资源浪费。

  3. 事件驱动:在处理网络操作时,传统 I/O 模型中常常需要轮询来检查连接是否有数据可读写,效率较低。

Java NIO 提供了非阻塞的 I/O 操作,通过 Channel 和 Selector 的概念,使得单个线程可以处理多个连接的 I/O 操作,减少了线程数量和系统资源的消耗。它采用了事件驱动的模型,通过选择器(Selector)监听多个通道的事件,并在事件发生时进行相应的处理,避免了不必要的轮询。

这些特性使得 Java NIO 更适用于处理大量连接、高并发的网络应用场景,提高了系统的效率和可伸缩性。虽然 Java NIO 相对于传统 I/O 更为复杂,但它带来了更高的性能和更好的资源利用率,因此得到了广泛的应用。

2.Talk is cheap.Show me your code.

2.1.传统代码实现传统阻塞I/O

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class SimpleEchoServer {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8080);
            System.out.println("Server started...");

            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("Client connected: " + clientSocket);

                BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                PrintWriter writer = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream()), true);

                String inputLine;
                while ((inputLine = reader.readLine()) != null) {
                    System.out.println("Received message from client: " + inputLine);
                    writer.println("Server echo: " + inputLine);
                }

                reader.close();
                writer.close();
                clientSocket.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

public class SimpleEchoClient {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost", 8080);
            PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            BufferedReader userInputReader = new BufferedReader(new InputStreamReader(System.in));

            String userInput;
            while ((userInput = userInputReader.readLine()) != null) {
                writer.println(userInput);
                String response = reader.readLine();
                System.out.println("Server response: " + response);
            }

            writer.close();
            reader.close();
            userInputReader.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这个简单的示例中,服务器接受客户端连接,读取客户端发送的消息并将其发送回客户端。客户端连接到服务器并发送消息,然后等待服务器返回的消息并打印。

请注意,这只是一个基于阻塞 I/O 的简单示例,实际应用中可能需要更多的错误处理、线程管理和优化。这种实现方式会为每个连接创建一个新的线程,当连接数增加时可能会导致线程资源的消耗过多。在高并发情况下,这种实现方式可能会遇到性能瓶颈。对于需要更高性能和可伸缩性的网络应用,可以考虑使用基于 Java NIO 的技术框架来实现。

2.2.NIO实现

下面是一个简单的基于 Java NIO 实现的简单通信示例,包括服务端和客户端:

NIO 服务端

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NIOServer {
    public static void main(String[] args) {
        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(8080));
            serverSocketChannel.configureBlocking(false);

            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            System.out.println("Server started...");

            while (true) {
                selector.select();

                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectedKeys.iterator();

                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();

                    if (key.isAcceptable()) {
                        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                        SocketChannel clientChannel = serverChannel.accept();
                        clientChannel.configureBlocking(false);
                        clientChannel.register(selector, SelectionKey.OP_READ);
                        System.out.println("Client connected: " + clientChannel.getRemoteAddress());
                    } else if (key.isReadable()) {
                        SocketChannel clientChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        int bytesRead = clientChannel.read(buffer);

                        if (bytesRead == -1) {
                            clientChannel.close();
                            key.cancel();
                            System.out.println("Client disconnected: " + clientChannel.getRemoteAddress());
                            continue;
                        }

                        buffer.flip();
                        byte[] bytes = new byte[buffer.remaining()];
                        buffer.get(bytes);
                        String message = new String(bytes).trim();
                        System.out.println("Received from client " + clientChannel.getRemoteAddress() + ": " + message);

                        // Echo back to the client
                        clientChannel.write(ByteBuffer.wrap(("Echo: " + message).getBytes()));
                    }

                    iterator.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

NIO 客户端

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NIOClient {
    public static void main(String[] args) {
        try {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.connect(new InetSocketAddress("localhost", 8080));

            String message = "Hello, server!";
            ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
            socketChannel.write(buffer);

            buffer.clear();
            socketChannel.read(buffer);
            buffer.flip();
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
            System.out.println("Server response: " + new String(bytes).trim());

            socketChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这个示例是一个简单的基于 Java NIO 的通信示例,包括一个非阻塞的 Echo Server 和一个客户端。服务端接受客户端连接并返回相同的消息。客户端连接到服务器并发送消息,然后等待服务器返回的消息。

在服务器端,通过 ServerSocketChannelSocketChannel 实现了非阻塞的通信,使用 Selector 监听多个通道的事件。在客户端,使用 SocketChannel 连接服务器,并进行数据的读写操作。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【昕宝爸爸小模块】深入浅出之Java 8中的 Stream

深入浅出之Java 8中的 Stream 一、&#x1f7e2;典型解析1.1 &#x1f7e0;Java 8中的Stream 都能做什么1.2 &#x1f7e0;Stream的创建 二、✅ Stream中间操作2.1 &#x1f7e0;Filter2.2 &#x1f7e0;Map2.3 &#x1f7e0;limit / skip2.4 &#x1f7e0;sorted2.5 &#x1…

FFmpeg编程录制音频(Mac OS)

之前我们使用FFmpeg命令行工具进行了简单的音视频操作&#xff0c;这次在Mac OS环境下编写代码实现简单的音频录制功能。 FFmpeg命令行音频录制 首先回顾一下Mac OS环境下简单的音频录制命令行实现&#xff1a; ffmpeg -f avfoundation -i ":0" -t 20 -acodec pcm…

电商平台如何引爆用户自主裂变:从策略到实践的全面解析

在当今竞争激烈的电商市场中&#xff0c;用户裂变成为企业持续增长的关键。如何引导用户自发传播&#xff0c;实现口碑与销量的双赢&#xff0c;是电商平台必须面对的挑战。本文将深入探讨电商平台如何通过精心策划和实施策略&#xff0c;激发用户自主裂变&#xff0c;助力企业…

蓝屏代码0x000007E解决办法

概述 出现该问题&#xff1a; 1、硬件冲突造成的蓝屏 驱动冲突&#xff1a;与其他设备或应用程序的驱动冲突可能会引起系统崩溃。 2、内存虚拟不足造成的蓝屏 错误配置&#xff1a;不正确的配置或设置可能会导致蓝屏错误。 3、超频后也可能出现蓝屏 CUP超频或者显卡超频后出现蓝…

水汽稳定度修正函数\Psi_q对潜热通量影响--模式验证工作

我之前提出了一个水汽通量廓线关系&#xff0c;这项工作偏理论&#xff0c;如果对下面说的背景不了解的话可以看下 https://agupubs.onlinelibrary.wiley.com/share/YNSG74MV8B8BAAUMCHN3?target10.1029/2022JD036708 那会没把提出的水汽稳定度修正函数加到CAS-ESM,当时对CAS-…

Ubuntu20.04-剪贴板

针对图形界面用户 1.两种方式 1.1 安装Parcellite 简单轻量级剪贴板管理器 sudo apt install parcellite 1.2 安装Gpaste 更强大的剪贴板管理器&#xff0c;包含历史记录和同步功能 sudo apt install gpaste

仿真验证方法(1)——动态验证

一、概述 1.1 验证的目的和方法 在现代集成电路设计中&#xff0c;验证所占工作量超过70%。验证要求真实而完备&#xff0c;它决定了设计的成败与成本。 验证的目的 原始描述是否正确&#xff1f;&#xff08;代码&#xff09; 逻辑功能是否正确&#xff1f;&#xff08;功能…

MATLAB--pie函数绘制分类饼图(1)--附案例代码

MATLAB–pie函数绘制分类饼图&#xff08;1&#xff09; 目录 MATLAB--pie函数绘制分类饼图&#xff08;1&#xff09;摘要1. pie函数概述2. 使用pie函数绘制分类图的步骤步骤1&#xff1a;准备数据步骤2&#xff1a;调用pie函数步骤3&#xff1a;定制图形&#xff08;可选&…

从事铁路工作保护足部,穿什么劳保鞋更安全

铁路运输在我国交通运输业中起着骨干作用&#xff0c;为国民经济的可持续发展和人口流动做出了巨大贡献。安全是铁路运输不可忽视的问题&#xff0c;在作业场地随处能见到“安全就是生命&#xff0c;责任重于泰山”的安全标语&#xff0c;由此可见安全问题是放在首位的。 铁路施…

2023年全球软件质量效能大会(QECon上海站):核心内容与学习收获(附大会核心PPT下载)

会议聚焦于软件质量和效能的提升。在智能时代&#xff0c;随着数字化的深入人心&#xff0c;软件正在随着云计算、移动互联网、物联网等的发展而不断进化&#xff0c;软件对企业的发展愈加重要&#xff0c;大家对软件的质量要求也在从传统功能、性能、安全这些基础层面向着用户…

GVM垃圾收集器

Serial收集器&#xff08;新生代&#xff09; Serial&#xff08;串行&#xff09;收集器是最基本、历史最悠久的垃圾收集器&#xff0c;采用“标记-复制”算法负责新生代的垃圾收集。它是Hotspot虚拟机运行在客户端模式下的默认新生代收集器。 它是一个单线程收集器。它会使用…

C桑(Cython)从入门到入土(2): np数组操作对比

C桑(Cython)从入门到入土 2. np数组操作对比 Node sc518 Copy has image data of type unsigned long long实际上, &#x1f446;&#x1f3fb;这个错误是我探索Cython的缘起… code1: Form: 更现代的方法是使用内存视图而不是指针&#xff1a; cdef np.uint32_t[:,:,::1] …

大模型学习产品,一个月顶一年 | 对话网易有道周枫

OpenAI CEO奥特曼曾表示&#xff1a;“AI女友只不过是一个美丽的陷阱&#xff0c;AI教育才是最应该去发力的一个领域。” 场景的确定性&#xff0c;是OpenAI等一众公司尤为重视教育领域的原因所在。教与学是教育场景中的核心&#xff0c;但再将两个字进行拆解&#xff0c;教学…

展望2024:9大要点把握PLM软件趋势,云PLM领导者Arena

2023年《质量强国建设纲要》&#xff08;以下简称《纲要》&#xff09;的推出&#xff0c;再次确定了中国要走上制造业高质量发展之路的决心。《纲要》指出要深入实施质量强国战略&#xff0c;加快传统制造业技术迭代和质量升级&#xff0c;推动工业品质量迈向中高端。当前&…

蓝桥杯基础知识3 memset()

蓝桥杯基础知识3 memset() #include <bits/stdc.h> using namespace std;int main(){int a[5]; //随机数for(int i 0;i < 5; i)cout << a[i] << \n;cout << \n;memset(a, 0, sizeof a); //0for(int i 0;i < 5; i)cout << a[i] << …

高德打车引入“红绿灯倒计时”能力,算力技术升级打车体验

打到的车还有多久能到&#xff1f;接驾车辆原地不动是什么原因&#xff1f;乘客在打车时&#xff0c;常常因为无法了解实时接驾路况&#xff0c;容易出现“等车焦虑”。 如今&#xff0c;高德打车已全面应用“红绿灯倒计时”能力&#xff0c;让乘客在等车时就能掌握接驾路况&am…

Qt QTableWidget表格控件

文章目录 1 属性和方法1.1 行列数目和行表头和列表头1.2 单元格1.3 隔行交替背景色1.4 选择模式和选择行为1.5 设置样式表 2 实例2.1 布局2.2 代码实现 QTableWidget是Qt中的表格控件。 1 属性和方法 QTableWidget有很多属性和方法&#xff0c;完整的可查看帮助文档。 在窗口…

时间序列预测 — VMD-LSTM实现单变量多步光伏预测(Tensorflow):单变量转为多变量预测多变量

专栏链接&#xff1a;https://blog.csdn.net/qq_41921826/category_12495091.html 专栏内容 所有文章提供源代码、数据集、效果可视化 文章多次上领域内容榜、每日必看榜单、全站综合热榜 时间序列预测存在的问题 现有的大量方法没有真正的预测未来值&#xff0c;只是用历史数据…

STM32L051使用HAL库操作实例(14)- ADC采集电压

目录 一、前言 二、ADC外设简要说明 三、STM32CubeMX配置&#xff08;本文使用的STM32CubeMX版本为6.1.2&#xff09; 1.MCU选型 2.时钟使能 3.外部时钟配置 4.串口配置 5.ADC引脚配置 6.配置STM32CubeMX生成工程文件 7.点击GENERATE CODE生成工程文件 四、工程源码 …

20240112让移远mini-PCIE接口的4G模块EC20在Firefly的AIO-3399J开发板的Android11下跑通【DTS部分】

20240112让移远mini-PCIE接口的4G模块EC20在Firefly的AIO-3399J开发板的Android11下跑通【DTS部分】 2024/1/12 16:20 https://blog.csdn.net/u010164190/article/details/79096345 [Android6.0][RK3399] PCIe 接口 4G模块 EC20 调试记录 https://blog.csdn.net/hnjztyx/artic…