当前位置: 首页 > news >正文

Java NIO 应知应会 (一)

Java NIO

NIO(New IO),New 相对传统的阻塞IO而言,Java 1.4版本开始引入的一个新的I/O AP,它提供了一种不同于传统Java IO和网络API的编程模型。

NIO是面向缓存区,这使得它可以更好地支持非阻塞I/O操作,在网络编程方面尤其在处理大量连接时更加高效。

NIO经常被误解为Non-blocking IO,即非阻塞IO,这是不准确的,因为NIO提供了多种模式,包括阻塞和非阻塞。

本文主要内容包含NIO 核心组件

  • Channel
  • Buffer
  • Selector

Channel

Channel是进行I/O操作的通道(IO不限于文件IO,网路IO等),它类似于传统的流(Stream),但有一些关键的区别

  • Channel是全双工的,既可以读,也可以写
  • Channel 所有的读写都是通过Buffer 进行的
  • Channel 支持非阻塞模式,当然也支持阻塞模式(这是为什么NIO 翻译为Non-blocking IO不严谨的原因)

Channel 常见实现类

FileChannel :它提供了对文件进行随机访问的能力
DatagramChannel: 用于通过UDP协议在网络上发送和接收数据
SocketChannel:用于通过TCP协议在网络上建立客户端连接并进行通信
ServerSocketChannel:用于监听传入的TCP连接请求,类似于Web服务器的功能

简单的文件读取例子

   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();

Buffer

Buffer 本质上是一块内存区域,可以用于读取数据和写入数据,比传统的流(Stream)更加高效。

Buffer 相关基本概念

  • Capacity
    缓冲区能够容纳的最大数据量
  • Limit
    缓冲区当前可读或可写的最大位置
  • Position
    当前读/写操作的位置。每次读/写操作后,位置会自动增加。

在这里插入图片描述

主要方法

  • flip(): 切换为读模式,调用flip()会将位置设置回 0,并将limit设置为刚刚位置所在的地方(position)

  • clear(): 清空缓冲区,位置将被设置回 0,limit将被设置为Capacity,实际上数据没有真正清除

  • compact(): 将未读的数据复制到缓冲区起始位置,然后将position设为未读数据的数量,limit保持不变。

  • mark() 和 reset(): 设置和重置position到之前标记的位置。

  • rewind(): 将position设为0,并保持limit不变,用于重新读取整个缓冲区。

  • hasRemaining(): 判断是否有剩余的元素可以读取。

  • remaining(): 返回还可以读取或写入的元素数量。

  • 分配Buffer

ByteBuffer buf = ByteBuffer.allocate(48);
  • 从Channel读取
int bytesRead = inChannel.read(buf); //read into buffer.

不同类型的 Buffer

  • ByteBuffer
  • CharBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer

以ByteBuffer为例,ByteBuffer其实是抽象类,它有两种实现DirectByteBufferHeapByteBuffer

  • DirectByteBuffer

    直接在操作系统分配的内存中创建,而不是在Java堆空间中。这意味着它不受Java垃圾回收机制的影响。开发者需要手动释放内存,如果使用不当,可能会导致内存泄漏

    ByteBuffer.allocateDirect(int capacity)方法来创建一个DirectByteBuffer实例

  • HeapByteBuffer

    HeapByteBuffer是在Java堆内存中分配的。这意味着它可以被垃圾收集器管理。

    性能特点:
    在大多数情况下,对于小规模的数据处理,HeapByteBuffer的性能足够好,因为它避免了与操作系统交互带来的开销。

    在涉及大量I/O操作或需要高效内存访问的情况下,HeapByteBuffer可能不如DirectByteBuffer高效

    使用ByteBuffer.allocate(int capacity)方法来创建一个HeapByteBuffer实例。

Selector

Selector可以检查一个或多个 Java NIO 通道(Channel)实例,
并确定哪些通道已准备好进行例如读取或写入操作,NIO selector 使用单线程就可以处理大量并发连接时。

  • 多路复用:Selector可以同时监控多个通道的状态变化,如读就绪、写就绪等。
  • 非阻塞I/O:结合非阻塞模式的通道使用,可以在没有数据可读或可写时立即返回,而不是阻塞等待。
  • 事件驱动:当有感兴趣的事件发生时,Selector会通知应用程序,应用进行相应读写事件处理。

事件类型

  • SelectionKey.OP_CONNECT
  • SelectionKey.OP_ACCEPT
  • SelectionKey.OP_READ
  • SelectionKey.OP_WRITE

使用步骤

  • 创建 Selector
  • 打开 Channel 并设置为非阻塞模式
  • 将 Channel 注册到 Selector 上,并指定感兴趣的事件类型
    在循环中调用 select() 方法,等待事件发生
    处理事件

核心代码

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<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> 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://www.mrgr.cn/news/59865.html

相关文章:

  • QT 机器视觉 1.相机类型
  • H5实现PDF文件预览,使用pdf.js-dist进行加载
  • 第十八届联合国世界旅游组织/亚太旅游协会旅游趋势与展望大会在广西桂林开幕
  • xxl-job java.sql.SQLException: interrupt问题排查
  • 在Selenium中有哪些元素对象操作方法?( ̄﹃ ̄)
  • Python监听指定路径下文件夹变化
  • FFmpeg 4.3 音视频-多路H265监控录放C++开发六,使用SDLVSQT显示yuv文件
  • UE ---- 射击游戏
  • 【Linux网络】传输层协议UDP与TCP
  • Mochi 1:AI视频生成领域的创新与应用
  • 绝了,这款播放器让发烧友疯狂种草,堪称音乐神器
  • 从零入门扣子Bot开发
  • Map和Set(数据结构)
  • 网络学习/复习2套接字
  • Linux基础-基础命令和相关知识4
  • 实现mysql和es的数据同步以及es的集群
  • 刷c语言练习题13(牛客网)
  • 【数据结构与算法】《Java 算法宝典:探秘从排序到回溯的奇妙世界》
  • 银河麒麟V10系统下libopenblas.so.0和libllmlmf库的安装
  • QT 实现自定义动态选择指示器
  • GPU的使用寿命可能只有1~3年
  • SpringBoot整合API接口做快递智能识别
  • 蓝桥杯普及题
  • Python实现基于WebSocket的stomp协议调试助手工具
  • 软硬链接与动静态库的加载
  • 鹏哥C语言95---第17次作业:指针初阶+结构体