4.6 Java高级之NIO


概述

在这里插入图片描述

NIO概述

在这里插入图片描述在这里插入图片描述

  • NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作
  • NIO:new I/O或者非阻塞式IO
  • 文件来自磁盘或者网络

字节流与NIO比较

在这里插入图片描述

  • 字节流:理解为水管里字节流在流动,即直接面对字节数据流动(byte数组),且数据传输是单向的

  • NIO:如图,需要建立通道,通道用于连接源地点和目标地点,只是铁轨,没有火车(缓冲区),本身没法传输数据

  • NIO:通道+缓冲区(负责存储数据,火车 ),双向传输

在这里插入图片描述- Buffer子类与通道交互(Buffer 主要用于与NIO 通道进行交互,数据是从通道读入缓冲区,从缓冲区写入通道中的)

  • boolean除外
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

  • 关注缓冲区的核心属性

  • 缓冲区底层是数组,所以大小不可改变

  • 被遗忘状态指的是指针位置,容量,limit等未知

缓冲区编程

API

在这里插入图片描述

实例

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • rewind指针重置

mark方法

在这里插入图片描述
在这里插入图片描述

put方法

在这里插入图片描述

在这里插入图片描述

直接缓冲区与非直接缓冲区

在这里插入图片描述
在这里插入图片描述

非直接缓冲区

在这里插入图片描述- 应用程序与磁盘间无法直接传输文件,应用程序要先向操作系统发起读数据请求(底层调用read,面向OS的I/O接口)

  • 用户地址空间(JVM内存)和内核地址空间(OS)

非直接缓冲区实例

  • 参照缓冲区编程实例

直接缓冲区

在这里插入图片描述

在这里插入图片描述

  • 复制多余,要省去copy过程
  • JVM直接将缓冲区建立在OS的物理内存中
  • 直接缓冲区:直接面向内存中的缓冲区
  • 适用情况
    • 大数据,不想在JVM中开辟空间
    • 希望存放时间长的内容
  • 缺点:
    • 分配销毁资源较大,GC机制释放对物理内存映射文件的引用,才会释放物理内存
    • 不易控制(交付之后管不了,由OS决定后续了)

直接缓冲区实例

在这里插入图片描述

  • Path get(String first, String … more) : 用于将多个字符串串连成路径。
  • 通过如上方式进行字符串连接
    在这里插入图片描述
  • 红圈处对应
  • 内存映射文件(物理内存中文件,只有ByteBuffer支持)的另一种创建方式
  • 此处缓冲区放,缓冲区取,不需要Channel(因为映射同一个文件)
  • 若第一个红圈处只有write,代表通道只支持写,导致通过通道获取的内存映射文件也不支持读,所以要添加read权限
  • 存在不稳定的问题:反馈不及时,因为GC机制没有及时释放内存(参照直接缓冲区的不安全性)——》程序不能及时退出(那边还没接收)

通道

  • Channel 本身不能直接访问数据,Channel 只能与Buffer 进行交互
    在这里插入图片描述
    在这里插入图片描述

  • 通常情况:大量读写请求(CPU负责I/O控制)——》导致CPU占有率高——》不能处理其他事务,利用率低

  • 改进:DMA(向CPU申请权限,DMA负责I/O),DMA全名为直接存储器存储——》与内存直接进行交互

  • 问题:过多请求——》DMA总线过多,冲突

  • 解决方法:

    • 通道:相较于DMA,独立的处理器,专门负责I/O,不需要申请权限

API

在这里插入图片描述
在这里插入图片描述

通道间数据传输

在这里插入图片描述

  • to和from对称关系,上述两种写法同样效果
  • 遮挡处使用create_new:若2.mkv存在就报错,如果使用create,代表存在则覆盖

利用通道完成复制

在这里插入图片描述

异常处理

在这里插入图片描述

分散读取与聚集写入

在这里插入图片描述
在这里插入图片描述

  • 将通道数据分散到多个缓冲区(依次填满
  • 多个缓冲区——》通道
  • 和之前程序不同之处:操作缓冲区——》操作缓冲区数组

字符集

在这里插入图片描述
在这里插入图片描述

  • 上述代码查看支持的字符集
    在这里插入图片描述- 首先获取编码器,解码器,然后创建缓冲区并放置数据,然后切换读模式,最后进行编码
    在这里插入图片描述- 编码:实质是字符buffer转字节buffer(转换为对应数值,存到底层)

  • 注意flip的使用及位置

  • 编码与解码对应,不然乱码

  • 以上为文件通道FileChannel

阻塞式网络通信

客户端

在这里插入图片描述- 添加反馈如下,注意有要shutdown方法,表示接收完毕,图中没有显示

在这里插入图片描述

  • 网络地址:套接字
  1. 获取通道
  2. 分配指定大小的缓冲区
  3. 从本地读取文件(FileChannel)——》数据读到缓冲区中(切换模式,读取到SocketChannel),边读边写
  4. 关闭通道
  • 实际读取字节数(len)

服务端

在这里插入图片描述在这里插入图片描述

  • ServerSocketChannel
  • 只需要指定端口号
  1. 获取通道
  2. 绑定连接
  3. 获取客户端连接的通道
  4. 接收客户端数据,并保存到本地
  5. 关闭通道
  • 服务端:接收完毕,发送反馈给客户端

  • 客户端:告诉服务端发完了

非阻塞式网络通信(❤)

在这里插入图片描述- 利用Selector 可使一个单独的线程管理多个Channel

  • Selector 是非阻塞IO 的核心
  • 使用NIO完成网络通信(实质数据传输)的三个组件
  • SelectableChannel抽象类
  • 非阻塞式相较于网络通信,所以FileChannel不能切换为非阻塞式模式

图解

在这里插入图片描述

  • 传统I/O:
  • 类比本地系统——》服务端系统上同样有用户地址空间和内核地址空间,同样copy
  • 服务器不能确认客户端读写请求的真实有效(有无数据)——》服务端线程一直处于阻塞,要等待有数据,才开始工作
  • 客户端发送数据,先到内核地址空间(读取内核地址空间判断有无数据)——》有数据,copy到用户地址空间
  • 大量请求——》排队,先来后到
  • 为每一个请求分配一个线程,多线程解决IO阻塞问题——》但线程数量有限

在这里插入图片描述

  • 非阻塞式
    • 选择器:每个通道注册到选择器,监控通道I/O状态(读写,连接,接收数据状态)
    • 某通道上某请求事件准备就绪时(数据准备就绪),选择器才会将任务分配到服务端的一个或多个线程上,再去运行

客户端

在这里插入图片描述

  1. 获取通道
  2. 切换为非阻塞模式
  3. 分配缓冲区
  4. 发送数据给服务端
  5. 关闭通道

服务端

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  1. 获取通道
  2. 切换为非阻塞模式
  3. 绑定连接
  4. 获取选择器,注册,选择键(多个状态监听,使用位或)
  • 获取所有监听的事件(iterator遍历)

  • 接收就绪——》再接收(accept)客户端连接的套接字

  • 客户端通道也需要切换为非阻塞式模式

  • 监听两种状态(接收就绪与读就绪)

  • 用完SelectionKey要取消掉(remove),不然一直有效,理由如下

  • 某个通道已经处于连接完成状态,不取消——》下一次依然显示连接完成状态,继续执行对应逻辑

  • 先启动服务端,然后客户端

  • while轮询状态,谁就绪,处理谁

  • 聊天室的雏形

  • 改进:对于不同的就绪状态,分配到多个线程执行后续任务

UDP

  • 把发送内容都打成包发送过去,目的地相同
  • 阻塞式轮询地获取就绪状态

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

管道

  • 单向数据传输

在这里插入图片描述

在这里插入图片描述

  • 可以两个线程共用一个pipe
  • 一个发送,一个接收
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值