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 clientclientChannel.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 连接服务器,并进行数据的读写操作。

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

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

相关文章

Python-动态烟花【附完整源码】

烟花代码 运行效果&#xff1a;Python动态烟花代码 import pygame from random import randint from random import uniform from random import choice import math vector pygame.math.Vector2 # 重力变量 gravity vector(0, 0.3) # 控制窗口的大小 DISPLAY_WIDTH DISP…

C#核心--实践小项目(贪吃蛇)

C#核心实践小项目 -- 贪吃蛇 必备知识点--多脚本文件 &#xff08;可观看CSharp核心--52集进行了解&#xff09; 必备知识点--UML类图 必备知识点--七大原则 贪吃蛇 项目展示 控制方向的是&#xff1a;WSAD 确定键是&#xff1a;J 需求分析&#xff08;UML类图&#xff09…

第11章 GUI Page495~496 步骤三十一:另存为别的文件

当前的TrySaveFile(bool hint_on_dirty true)有两个特征无法满足“另存”的需求&#xff1a; 一&#xff0c;TrySaveFile仅在数据为“新”的时候才提问用户输入文件名。而“另存”总是要求用户输入一个文件名&#xff0c;多以它总应该弹出一个文件选择对话框&#xff0c;这也…

【网络安全】【密码学】【北京航空航天大学】实验二、数论基础(中)【C语言和Java实现】

实验二、数论基础&#xff08;中&#xff09; 一、实验内容 1、扩展欧几里得算法&#xff08;Extended Euclid’s Algorithm&#xff09; &#xff08;1&#xff09;、算法原理 已知整数 a , b ,扩展的欧几里得算法可以在求得 a , b 的最大公约数的同时&#xff0c;找到一对…

LeetCode[105] 从前序与中序遍历序列构造二叉树

给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,20,7] 输出: [3,9,20,null,null,15,7] …

使用Java连接MongoDB (6.0.12) 报错

报错&#xff1a; Exception in thread "main" com.mongodb.MongoCommandException: Command failed with error 352: Unsupported OP_QUERY command: create. 上图中“The client driver may require an upgrade”说明了“客户端驱动需要进行升级”&#xff0c;解…

What does `rpm -ivh` do?

rpm -ivh 安装 并 显示安装进度 (–install–verbose–hash) rpm -ivh /media/cdrom/RedHat/RPMS/samba-3.0.10-1.4E.i386.rpm 安装rpm -ivh --relocate //opt/gaim gaim-1.3.0-1.fc4.i386.rpm 指定安装到 /opt/gaim[Ref] rpm -uvh和-ivh有什么区别以及zabbix 安…

使用BeanShell写入内容到文件【JMeter】

一、前言 ​ 在我们日常工作中&#xff0c;可能会遇到需要将请求返回的数据写入到文件中。在我们使用JMeter进行性能测试时&#xff0c;就经常能够遇到这种情况。要想达到这种目的&#xff0c;我们一般采取BeanShell后置处理器来将内容写入到文件。 二、提取 ​ 在目前大多数的…

基于多智能体点对点转换的分布式模型预测控制

matlab2020正常运行 基于多智能体点对点转换的分布式模型预测控制资源-CSDN文库

对于软件测试的认识和了解

对软件测试的认识&#xff1a; 软件测试要求开发人员避免测试自己开发的程序。从心理学角度讲&#xff0c;这是很有道理的。特别是一个相对复杂的系统&#xff0c;开发人员在刚刚开发完成的时候&#xff0c;尚沉浸于对自己设计的回味之中。此时去测试的话往往会侧重于程序本身的…

CSS3简单运用过渡元素(transition)

CSS3过渡 概念&#xff1a;在CSS3中&#xff0c;我们可以使用transition属性将元素的某一个属性从“一个属性值”在指定的时间内平滑地过渡到“另一个属性值”&#xff0c;从而实现动画效果。 CSS3变形&#xff08;transform)呈现的仅仅是一个结果&#xff0c;而CSS过渡&…

WPS - 表格虚线变成实线解决方案(Office 同上)

1、选中表格区域&#xff0c;在表格中选中需要调整为实线的表格区域 2、点击设置单元格格式&#xff0c;鼠标进行右击并点击设置单元格格式选项 3、选择实线&#xff0c;在单元格格式下的边框&#xff0c;调整到实线 4、设置为实线&#xff0c;即可将表格的虚线设置为实线

AI系统ChatGPT网站系统源码AI绘画详细搭建部署教程,支持GPT语音对话+DALL-E3文生图+GPT-4多模态模型识图理解

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作Ch…

【AI视野·今日NLP 自然语言处理论文速览 第七十四期】Wed, 10 Jan 2024

AI视野今日CS.NLP 自然语言处理论文速览 Wed, 10 Jan 2024 Totally 38 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Model Editing Can Hurt General Abilities of Large Language Models Authors Jia Chen Gu, Hao Xiang Xu, J…

Qt QGraphicsItem获取鼠标位置对应图像坐标

本次使用了QGraphicsView来加载图像&#xff0c;然后给其设置了一个QGraphicsScene场景&#xff0c;再给场景添加了一个自定义的QGraphicsItem&#xff0c;在其中重写了paint事件&#xff0c;用来重绘图像。 正常情况时&#xff0c;QGraphicsItem上图像的有效区域QRect大小和QG…

基于爬虫和Kettle的豆瓣电影的采集与预处理

一&#xff1a;爬虫 1、爬取的目标 将豆瓣电影网上的电影的基本信息&#xff0c;比如&#xff1a;电影名称、导演、电影类型、国家、上映年份、评分、评论人数爬取出来&#xff0c;并将爬取的结果放入csv文件中&#xff0c;方便存储。 2、网站结构 图1豆瓣网网站结构详…

Web前端 ---- 【Vue3】Proxy响应式原理

目录 前言 安装Vue3项目 安装 Proxy 语法格式 前言 从本文开始进入vue3的学习。本文介绍vue3中的响应式原理&#xff0c;相较于vue2中通过object.defineProperty&#xff08;vue2中的响应式&#xff09;来实现响应式&#xff0c;vue3中换成了Proxy来进行实现。 安装Vue3项目…

Linux---gcc编译

目录 前言 一、gcc编译 二、程序的编译过程 三、gcc查看编译过程 1.预处理阶段 2.编译 3.汇编 4.链接 动静态库链接的内容 动静态库链接的优缺点 5.总结记忆 前言 在前面我们学会使用vim对文件进行编辑&#xff0c;如果是C或者C程序&#xff0c;我们编辑好了内容…

数据结构二叉树创建及例题(上)

今天就带领大家来到树的世界,树无论是在考试上还是实际学习方面都是比较重点的,大家在这块知识要花时间搞懂. 文章目录 前言 一、树的二叉链表定义 二、二叉树三种遍历方式(递归方式) 1.先序遍历方式(根左右) 2.中序遍历方式(左根右) 3.后序遍历方式(左右根) 三、二叉树的…

单片机I/O口驱动MOS管

自记录&#xff1a; 使用单片机做一个PLC,输出可如下两种情况&#xff1a; 单片机I/O口驱动&#xff0c;为什么一般都选用三极管而不是MOS管&#xff1f; 1.单片机的IO口&#xff0c;有一定的带负载能力。但电流很小&#xff0c;驱动能力有限&#xff0c;一般在10-20mA以内。…