Java NIO

NIO: 同步非阻塞,面向缓冲区,基于通道的io操作。

首先了解阻塞和非阻塞,同步和异步的概念

阻塞和非阻塞(基于进程):

阻塞:调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回

非阻塞:指在不能立刻得到结果之前,该调用不会阻塞当前线程。

同步和异步(基于应用程序):

同步:主动请求并等待I/O操作完毕

异步:主动请求数据后,便可以继续处理其它任务,随后等待I/O,操作完毕的通知

NIO三大核心部分:Buffer(缓冲区) 、Channel(通道) 、Selector(选择器)

它们之间的关系:

  

Buffer(缓冲区) : 一个可读写数据的内存块,可以理解成一个容器对象(含数组),该对象提供了一组方法,可以更轻松使用内存块

常用Buffer子类一览

ByteBuffer,存储字节数据到缓冲区

ShortBuffer,存储字符串数据到缓冲区

CharBuffer,存储字符数据到缓冲区

IntBuffer,存储整数数据到缓冲区

LongBuffer,存储长整型数据到缓冲区

DoubleBuffer存储小数到缓冲区 FloatBuffer,存储小数到缓冲区

Buffer类定义了所有的缓冲区都具有的四个属性来提供关于其所包含的数据元素的信息

Capacity:容量,即可以容纳的最大数据量;在缓冲区创建时被设定并且不能改变

Limit:表示缓冲区的当前终点,不能对缓冲区超过极限的位置进行读写操作。且极限是可以修改的

Position:位置,下一个要被读或写的元素的索引,每次读写缓冲区数据时都会改变改值,为下次读写作准备

Mark:标记

 

Channel(通道): NIO的通道类型于流,但通道可以同时读写,流只能读或者只能写

Selector(选择器): 检测多个注册的通道上是否有事件发生

NIO与BIO对比:

面向缓冲与面向流

IO是面向流的.NIO是面向缓冲区的。Java IO面向流意味着毎次从流中读一个成多个字节,直至读取所有字节,它们没有被缓存在任何地方,此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的教据,需要先将它缓存到一个缓冲区。Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,霱要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数裾。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据

NIO:一个线程管理多个连接
BIO:一个线程管理一个连接

 

11-13
Java NIO(New I/O)是Java 1.4引入的新的I/O API,用于替代标准的Java I/O API。它提供了非阻塞I/O操作,能显著提高程序的性能和可扩展性,尤其适用于处理大量并发连接的场景。 ### 核心组件 - **Channel(通道)**:Channel是对传统I/O中流的模拟,用于在缓冲区和实体(如文件、套接字)之间传输数据。常见的Channel实现有FileChannel、SocketChannel、ServerSocketChannel和DatagramChannel等。例如,FileChannel用于文件读写,SocketChannel用于TCP网络通信。 - **Buffer(缓冲区)**:Buffer是一个用于存储特定基本类型数据的容器。所有的缓冲区都是Buffer抽象类的子类,如ByteBuffer、CharBuffer、IntBuffer等。使用时,数据先被写入Buffer,再从Buffer读取到Channel,反之亦然。 - **Selector(选择器)**:Selector是Java NIO实现非阻塞I/O的关键。它允许一个线程处理多个Channel的I/O事件。通过将多个Channel注册到一个Selector上,Selector可以不断轮询这些Channel,当某个Channel有可用的I/O操作时,就会被Selector选中,从而实现单线程处理多个连接的目的。 - **SelectionKey(选择键)**:SelectionKey用于维护Selector和SelectableChannel的关系,每个Channel注册到Selector时都会产生一个SelectionKey,它聚合了Channel和Selector,有点类似EventKey。通过SelectionKey可以获取对应的Channel和Selector,还可以设置和查询感兴趣的I/O事件类型,如读、写、连接和接受连接事件等 [^1]。 ### 使用指南 #### 1. 使用FileChannel进行文件读写 ```java import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class FileChannelExample { public static void main(String[] args) { try (FileInputStream fis = new FileInputStream("input.txt"); FileOutputStream fos = new FileOutputStream("output.txt"); FileChannel inChannel = fis.getChannel(); FileChannel outChannel = fos.getChannel()) { ByteBuffer buffer = ByteBuffer.allocate(1024); while (inChannel.read(buffer) != -1) { buffer.flip(); // 切换为读模式 outChannel.write(buffer); buffer.clear(); // 清空缓冲区,准备下一次写入 } } catch (IOException e) { e.printStackTrace(); } } } ``` #### 2. 使用Selector实现非阻塞网络编程 ```java import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; public class NioServerExample { public static void main(String[] args) { try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); Selector selector = Selector.open()) { serverSocketChannel.socket().bind(new InetSocketAddress(8080)); serverSocketChannel.configureBlocking(false); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); 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()) { ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel(); SocketChannel socketChannel = serverChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesRead = socketChannel.read(buffer); if (bytesRead > 0) { buffer.flip(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); System.out.println(new String(data)); } } keyIterator.remove(); } } } catch (IOException e) { e.printStackTrace(); } } } ``` ### 原理 Java NIO的非阻塞I/O原理基于操作系统的I/O多路复用机制。在传统的阻塞I/O模型中,一个线程只能处理一个连接,当线程在等待某个连接的数据时会被阻塞,无法处理其他连接。而在Java NIO中,Selector利用操作系统提供的I/O多路复用功能,如Linux的select、poll和epoll,通过一个线程监控多个Channel的I/O状态。当某个Channel有数据可读或可写时,Selector会感知到并通知应用程序进行相应的处理,从而实现单线程处理多个连接,提高了系统的并发处理能力。 ### 应用场景 - **网络编程**:在构建高性能的网络服务器时,如Web服务器、聊天服务器、游戏服务器等,Java NIO的非阻塞I/O特性可以显著减少线程数量,降低系统资源消耗,提高服务器的并发处理能力。 - **文件处理**:对于大文件的读写操作,使用FileChannel和ByteBuffer可以提高文件读写的效率,尤其是在需要随机访问文件内容时。 - **实时数据处理**:在处理实时数据流时,如视频流、音频流等,Java NIO可以高效地处理数据的传输和处理,确保数据的实时性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值