NIO概述

【NIO详解】NIO概述 一、NIO简介Java NIO,通常称为 New IO 或 No Block IO, 是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。注:JDK1.4的版本为 NIO 1.0, 而JDK7的版本为 NIO 2.0二、NIO与传统IO的区别1.传统I 阅读详情

简介

Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。

Java NIO: Channels and Buffers(通道和缓冲区)
标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。

Java NIO: Non-blocking IO(非阻塞IO)
Java NIO可以让你非阻塞的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。

Java NIO: Selectors(选择器)
Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。

Java NIO 由以下几个核心部分组成:
Channels
Buffers
Selectors

Channel和Buffer有好几种类型。下面是JAVA NIO中的一些主要Channel的实现:
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel
正如你所看到的,这些通道涵盖了UDP 和 TCP 网络IO,以及文件IO。

与这些类一起的有一些有趣的接口,但为简单起见,我尽量在概述中不提到它们。本教程其它章节与它们相关的地方我会进行解释。

以下是Java NIO里关键的Buffer实现:
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
这些Buffer覆盖了你能通过IO发送的基本数据类型:byte, short, int, long, float, double 和 char。

Java NIO 还有个 MappedByteBuffer,用于表示内存映射文件, 我也不打算在概述中说明。

Selector
Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。例如,在一个聊天服务器中。

这是在一个单线程中使用一个Selector处理3个Channel的图示:
在这里插入图片描述
要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。

Buffer

为了理解Buffer的工作原理,需要熟悉它的三个属性:
capacity
position
limit
在这里插入图片描述
capacity
作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

position
当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.

当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

limit
在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。

当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)

Buffer的类型
Java NIO 有以下Buffer类型

ByteBuffer
MappedByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer

buffer常用方法说明

flip()方法
flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。

换句话说,position现在用于标记读的位置,limit表示之前写进了多少个byte、char等 —— 现在能读取多少个byte、char等。

rewind()方法
Buffer.rewind()将position设回0,所以你可以重读Buffer中的所有数据。limit保持不变,仍然表示能从Buffer中读取多少个元素(byte、char等)。

clear()与compact()方法
一旦读完Buffer中的数据,需要让Buffer准备好再次被写入。可以通过clear()或compact()方法来完成。

如果调用的是clear()方法,position将被设回0,limit被设置成 capacity的值。换句话说,Buffer 被清空了。Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据。
如果Buffer中有一些未读的数据,调用clear()方法,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。
如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先先写些数据,那么使用compact()方法。

compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。

mark()与reset()方法
通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position。例如:

buffer.mark();
//call buffer.get() a couple of times, e.g. during parsing.
buffer.reset();  //set position back to mark.

equals()与compareTo()方法
可以使用equals()和compareTo()方法两个Buffer。

equals()
当满足下列条件时,表示两个Buffer相等:

有相同的类型(byte、char、int等)。
Buffer中剩余的byte、char等的个数相等。
Buffer中所有剩余的byte、char等都相同。
如你所见,equals只是比较Buffer的一部分,不是每一个在它里面的元素都比较。实际上,它只比较Buffer中的剩余元素。

compareTo()方法
compareTo()方法比较两个Buffer的剩余元素(byte、char等), 如果满足下列条件,则认为一个Buffer“小于”另一个Buffer:

第一个不相等的元素小于另一个Buffer中对应的元素 。
所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。

Channel

Java NIO的通道类似流,但又有些不同:

既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
通道可以异步地读写。
通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。
正如上面所说,从通道读取数据到缓冲区,从缓冲区写入数据到通道。如下图所示:

在这里插入图片描述
Channel的实现
这些是Java NIO中最重要的通道的实现:

FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel
FileChannel 从文件中读写数据。

DatagramChannel 能通过UDP读写网络中的数据。

SocketChannel 能通过TCP读写网络中的数据。

ServerSocketChannel可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

基本的 Channel 示例
下面是一个使用FileChannel读取数据到Buffer中的示例:

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

ByteBuffer buf = ByteBuffer.allocate(48);

int bytesRead = inChannel.read(buf);
while (bytesRead != -1) {

System.out.println("Read " + bytesRead);
buf.flip();

while(buf.hasRemaining()){
System.out.print((char) buf.get());
}

buf.clear();
bytesRead = inChannel.read(buf);
}
aFile.close();

通道之间的数据传输

在Java NIO中,如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel(译者注:channel中文常译作通道)传输到另外一个channel。
transferFrom()

FileChannel的transferFrom()方法可以将数据从源通道传输到FileChannel中(译者注:这个方法在JDK文档中的解释为将字节从给定的可读取字节通道传输到此通道的文件中)。下面是一个简单的例子:

RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
FileChannel      fromChannel = fromFile.getChannel();

RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
FileChannel      toChannel = toFile.getChannel();

long position = 0;
long count = fromChannel.size();

toChannel.transferFrom(position, count, fromChannel);

transferTo()
方法的输入参数position表示从position处开始向目标文件写入数据,count表示最多传输的字节数。如果源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数。
此外要注意,在SoketChannel的实现中,SocketChannel只会传输此刻准备好的数据(可能不足count字节)。因此,SocketChannel可能不会将请求的所有数据(count个字节)全部传输到FileChannel中。

RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
FileChannel      fromChannel = fromFile.getChannel();

RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
FileChannel      toChannel = toFile.getChannel();

long position = 0;
long count = fromChannel.size();

fromChannel.transferTo(position, count, toChannel);

Selector

对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些资源(如内存)。因此,使用的线程越少越好。
但是,需要记住,现代的操作系统和CPU在多任务方面表现的越来越好,所以多线程的开销随着时间的推移,变得越来越小了。实际上,如果一个CPU有多个内核,不使用多任务可能是在浪费CPU能力。
仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道。事实上,可以只用一个线程处理所有的通道。
不管怎么说,关于那种设计的讨论应该放在另一篇不同的文章中。在这里,只要知道使用Selector能够处理多个通道就足够了。

Selector一起使用时,Channel必须处于非阻塞模式下。
这意味着不能将FileChannel与Selector一起使用,因为FileChannel不能切换到非阻塞模式。而套接字通道都可以。

为了将Channel和Selector配合使用,必须将channel注册到selector上。通过SelectableChannel.register()方法来实现,如下:

channel.configureBlocking(false);
SelectionKey key = channel.register(selector,
	Selectionkey.OP_READ);

四种事件用SelectionKey的四个常量来表示:
SelectionKey.OP_CONNECT 连接就绪
SelectionKey.OP_ACCEPT 接收就绪
SelectionKey.OP_READ 读就绪
SelectionKey.OP_WRITE 写就绪

如果你对不止一种事件感兴趣,那么可以用“位或”操作符将常量连接起来,如下:

int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

SelectionKey
在上一小节中,当向Selector注册Channel时,register()方法会返回一个SelectionKey对象。这个对象包含了一些你感兴趣的属性:

interest集合
ready集合
Channel
Selector
附加的对象(可选)

select()方法返回的int值表示有多少通道已经就绪。亦即,自上次调用select()方法后有多少通道变成就绪状态。
如果调用select()方法,因为有一个通道变成就绪状态,返回了1,若再次调用select()方法,如果另一个通道就绪了,它会再次返回1。如果对第一个就绪的channel没有做任何操作,现在就有两个就绪的通道,但在每次select()方法调用之间,只有一个通道就绪了。

selectedKeys()
一旦调用了select()方法,并且返回值表明有一个或更多个通道就绪了,然后可以通过调用selector的selectedKeys()方法,访问“已选择键集(selected key set)”中的就绪通道。如下所示:

Set selectedKeys = selector.selectedKeys();
当像Selector注册Channel时,Channel.register()方法会返回一个SelectionKey 对象。这个对象代表了注册到该Selector的通道。可以通过SelectionKey的selectedKeySet()方法访问这些对象。

wakeUp()
某个线程调用select()方法后阻塞了,即使没有通道已经就绪,也有办法让其从select()方法返回。只要让其它线程在第一个线程调用select()方法的那个对象上调用Selector.wakeup()方法即可。阻塞在select()方法上的线程会立马返回。

如果有其它线程调用了wakeup()方法,但当前没有线程阻塞在select()方法上,下个调用select()方法的线程会立即“醒来(wake up)”。

close()
用完Selector后调用其close()方法会关闭该Selector,且使注册到该Selector上的所有SelectionKey实例无效。通道本身并不会关闭。

完整的示例
这里有一个完整的示例,打开一个Selector,注册一个通道注册到这个Selector上(通道的初始化过程略去),然后持续监控这个Selector的四种事件(接受,连接,读,写)是否就绪。

Selector selector = Selector.open();
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
while(true) {
  int readyChannels = selector.select();
  if(readyChannels == 0) continue;
  Set selectedKeys = selector.selectedKeys();
  Iterator keyIterator = selectedKeys.iterator();
  while(keyIterator.hasNext()) {
    SelectionKey key = keyIterator.next();
    if(key.isAcceptable()) {
        // a connection was accepted by a ServerSocketChannel.
    } else if (key.isConnectable()) {
        // a connection was established with a remote server.
    } else if (key.isReadable()) {
        // a channel is ready for reading
    } else if (key.isWritable()) {
        // a channel is ready for writing
    }
    keyIterator.remove();
  }
}

参考资料

原文出处:http://ifeve.com/java-nio-vs-io/
IO/NIO https://blog.youkuaiyun.com/My_Confesser/article/details/52681660

Python实现课程时间表 用Python实现课程表功能 阅读详情

相关推荐

FMQL开发环境实战:从零构建国产FPGA SoC的软件基石

本文详细解析了构建国产复旦微FMQL FPGA SoC软件开发环境的完整流程。针对开发者在环境搭建中遇到的核心痛点,文章深入剖析了Procise、IAR与Vivado三大工具的协同角色与版本选择,提供了从软件下载、安装避坑到核心配置的实战指南,并总结了常见问题的排查方法,旨在帮助开发者高效跨过FMQL开发的“第一道坎”。

weixin_29215391的博客 125

Netty之前篇——NIO基础

以下内容由动脑five老师的笔记整理而来。 一、几个概念 1、阻塞与非阻塞 阻塞与非阻塞是描述进程在访问某个资源时,数据是否准备就绪的的一种处理方式。当数据没有准备就绪时: 阻塞:线程持续等待资源中数据准备完成,直到返回响应结果。 非阻塞:线程直接返回结果,不会持续等待资源准备数据结束后才响应结果。 2、同步与异步 同步与异步是指访问数据的机制,同步一般指主动请求并等待...

w1lgy的博客 481

USB的24脚和12脚TYPEC引脚定义

USB 是一种接口,用于将设备连接到计算机上。通过该连接,计算机可以向设备发送数据或检索来自设备的数据。USB 为开发者提供了一个标准接口,适用于多种不同类型的应用。借助于系统的设计过程,USB 设备易于连接和使用。本应用笔记会使该过程变得更加简单。以下是本应用笔记中会使用的概念:USB 历史USB 架构USB 物理接口USB 速度USB 电源USB 端点USB 通信协议USB 描述符USB 类设备USB 枚举与配置过程。

易板 1万+

NIO是什么?它与传统的IO有什么区别?

NIO(Non-blocking I/O)是Java 1.4版本引入的一种新的I/O模型,它通过引入非阻塞I/O、选择器、缓冲区和管道等新特性,显著提高了网络通信和文件操作的效率。虽然NIO在编程复杂度和内存消耗方面存在一定的局限性,但在高并发和大规模数据处理的场景下,NIO仍然是一个非常有效的解决方案。通过本文的介绍和示例代码,相信您对NIO有了更深入的理解。希望这些内容能够帮助您在实际开发中更好地应用NIO技术。15。

wang15510689957的博客 1974

Stata森林图进阶:个性化定制与高级技巧

本文详细介绍了Stata森林图的进阶技巧,包括个性化定制与高级应用。通过meta分析工具如metan命令,用户可以优化字体、颜色、坐标轴等视觉元素,提升森林图的专业性和可读性。文章还提供了黑白印刷设置、高分辨率导出等实用技巧,帮助科研人员制作符合学术出版要求的森林图。

ios99的博客 254

Sublime Text4代码配色自定义方案

关于Sublime Text对于我的使用体验,只能说内置的代码主题真的都太low了,一点都不好看。所以接下来我分享一下我自定义代码配色。当然,大家也可以通过我给的中文翻译注释来自定义自己喜欢的颜色。废话不多说,直接上代码直接将代码复制粘贴到:Preferences > Customize Color Scheme 即可。},"globals":"foreground": "var(white)", // 前景色。

追求细节,成就完美 6026

NIO图文详解

(1)阻塞I/O模型:阶段一和阶段二用户进程都处于阻塞状态,效率最低,适用于并发量低的小型网站,是java BIO的基础;(2)非阻塞I/O模型:阶段一用户进程处于非阻塞状态,但应用进程需不断轮询内核空间数据是否准备好,消耗大量CPU时间;阶段二用户进程处于非阻塞状态;(3)I/O复用模型:阶段一和阶段二用户进程都处于阻塞状态,但以较少的代价同时监听多个文件描述符,效率较高,适用于并发高的大中型网站,java NIO是实现I/O复用模型的基础;

qq_40439628的博客 3248

UCIE Specification详解(三)

Protocol Layer(协议层)以及Die-to-Die Adapter

Crazzy_M的博客 1752

Java NIO详解:新手完全指南

NIO(New I/O或Non-blocking I/O)是Java 1.4引入的一套全新的I/O API,为所有的原始类型提供缓冲区支持,使用它可以提供非阻塞式的高伸缩性网络和文件I/O操作。NIO被设计用来代替标准的Java I/O API(java.io包),提供了更高效的I/O操作方式。传统IO与NIO在设计理念和使用方式上有显著差异,下面是它们的主要区别: 2.1.2 NIO读取文件 3. NIO核心组件 Java NIO由三个核心组件组成,它们共同提供了一个完整的非阻塞I/O解决方案:Buff

yk_dflkg的博客 1542

ROS2 - 乐动激光雷达 LD06

STL-06P 主要由激光测距核心,无线传电单元,无线通讯单元,角度测量单元、电机驱动单元和机械外壳组成。STL-06P 测距核心采用 DTOF 技术,可进行每秒 5000 次的测距。每次测距时,雷达发射出红外激光,激光遇到目标物体后被反射到单光子接收单元。

机器人控制与仿真应用 3482

腾讯微搭低代码开发实战电子书:医疗挂号小程序

本书通过一个完整的“医疗挂号小程序”项目,深度讲解腾讯微搭(WeDa)低代码平台在复杂业务场景下的实战应用。从登录体系搭建、用户注册,到就诊人管理、科室排班与预约下单,全程遵循“配置+逻辑+实战”的思路,带领读者从零实现具备商业级可用性的医疗挂号小程序,掌握低代码开发的核心技巧与业务落地能力。

低代码布道师的博客 951

了解NIO的概述

同步与异步(synchronous/asynchronous) 同步: 调用方法之后,必须要得到一个返回值 异步: 调用方法之后,没有返回值,但是会有回调函数,回调函数指的是满足条件之后会自动执行的方法 阻塞与非阻塞 阻塞:如果没有达到方法的目的,就会一直停在那里(等待) , 例如: ServerSocket的accept()方法 非阻塞: 不管方法有没有达到目的,都直接往下执行(不等待) NIO 这是一个面向块的I/O系统,系统以块的方式处理数据 NIO之所以是同步,是因为它的accept/r

weixin_53589418的博客 232

一个严谨的STM32串口DMA发送&接收(1.5Mbps波特率)机制

本文描述串口DMA收/发机制设计,及STM32串口DMA收/发实现。

只要思想不滑坡,想法总比问题多。 5万+

java nio类_Java NIO类概述

本篇博客的初衷是记录了博主本次阅读系列博客(Java NIO入门教程详解–链接见文末)全文过程中的一些笔记,描述了Java NIO中核心类以及其方法的作用;Buffer 属性 - capacity:容量 - limit:上界,缓冲区的临界区,即最多可读到哪个位置 - position:下标,当前读取到的位置(例如当前读出第5个元素,则读完后,position为6) ...

weixin_32103009的博客 227

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

nio概述

Java NIO(New IO 或 Non Blocking IO)是从 Java 1.4 版本开始引入的一个新的 IO API,可以替代标准的 Java IO API。NIO 支持面向缓冲区的、基于通道的 IO 操 作。NIO 将以更加高效的方式进行文件的读写操作。 阻塞 IO 通常在进行同步 I/O 操作时,如果读取数据,代码会阻塞直至有可供读取的数据。同 样,写入调用将会阻塞直至数据能够写入。传统的 Server/Client 模式会基于 TPR (Thread per Request

Diligently 204

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

BIO和NIO的概述

xianrenqiu1234的博客 172

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

1.NIO概述


 
  
 
 
 
 
 
 
 
 
 
 
 

王屋山下的传说 96

day21 12NIO概述

qq_42722278的博客 133

Java NIO概述

第1章 Java NIO 概述 Java NIO(New IO 或 Non Blocking IO)是从 Java 1.4 版本开始引入的一个新的IO API,可以替代标准的 Java IO API。NIO 支持面向缓冲区的、基于通道的 IO 操 作。NIO 将以更加高效的方式进行文件的读写操作。 1.1 阻塞 IO 通常在进行同步 I/O 操作时,如果读取数据,代码会阻塞直至有可供读取的数据。同 样,写入调用将会阻塞直至数据能够写入。传统的 Server/Client 模式会基于 TPR(Thread p

qq_42522024的博客 264

NIO、AIO概述总结

经过前几天的学习,将BIO的基础知识总结完成,接下来今天我将总结学习NIO和AIO的知识点,在理解学习的基础上,去使用相关知识点进行编程学习。这次我将先总结NIO的知识点,再学习AIO的相关概念。 NIO NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通...

qq_51074048的博客 1980
上一篇: 当前主流服务注册中心对比
下一篇: Mysql常见考点
牧竹子
博客等级 码龄17年 572粉丝 233原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值