news 2026/2/3 3:15:56

Java中的NIO详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java中的NIO详解

一、NIO简介

NIO中的N为NEW, IO为INPUT/OUTPUT,也就是民间所说的Non-Blocking IO,它拥有高并发能力,到JDK1.7 出现了NIO2.0。

在单线程的情况下,当前的IO操作即使没有完成,当前线程也能做其他事情,不用等待某个操作涉及的数据全部完成再进行其他操作。具体解释为:NIO的非阻塞模式下,线程发送数据与接收数据都是通过通道进行的,线程只需要去查看是否有数据要处理,如果没有就直接返回,不会等待。

二、NIO架构设计

Java NIO的核心组件包括:Channel(通道),Buffer(缓冲区),Selector(选择器)。

1、缓冲区(内存区域)

它本质上就是一个数组,提供了对数据的结构化访问以及维护读写位置等功能。

(1)缓冲区的作用:负责与通道进行交互。在面向流的IO中我们可以直接把数据写到Stream对象里,而面向通道的IO则不行,线程需要先把数据写入到缓冲区,再将缓冲区里的数据写到通道对象里。

(2)缓冲区的类别:最常用的是ByteBuffer(字节缓冲区),其他的还有CharBuffer、ShortBuffer等。ByteBuffer除了具有一般缓冲的操作之外还提供了一些特有操作,方便网络读写。

2、通道

通过它传输数据,与流的不同之处在于,通道是全双工的,同时支持读写操作,而流只能在一个方向上移动。

通道的作用:用于在字节缓冲区和通道的另一侧的实体(通常是一个文件或者套接字)进行有效的数据传输。

3、多路复用器(选择器)

它会不断地轮询注册在它上面的通道,并且返回那些准备就绪的通道,以便进行后续的IO处理。对应linux操作系统中的epoll。

注意:服务器客户端可分别有自己的多路复用器(选择器)。

三、ServerSocketChannel和SocketChannel的区别

它们是一对,位于java.nio中的通信的类。其中ServerSocketChannel是服务器端用的通道,SocketChannel是服务端/客户端均可用的通道。使用的时候必须先建立ServerSocketChannel通道来等待客户端的连接。客户端则必须建立相对应的SocketChannel(客户端会给该通道随机分配一个端口号)来与服务器建立连接,服务器接收到客户端的连接后,创建一个新的SocketChannel(该端口号与ServerSocketChannel端口号相同)并通过ServerSocketChannel.accept()方法与客户端的SocketChannel建立连接,之后双方就可以进行通信了。即服务器端的每一个SocketChannel都唯一标识了一个客户端。

现在我们给出一个测试样例,代码分为客户端和服务端,将它们分别放在不同的linux机器上,进行远程调用。注意客户端中申请连接用的IP和PORT一定是跟服务器中绑定的相同,否则无法建立连接。

注意:需要关系两台测试机器的防火墙;确定端口未被占用。

客户端代码如下:

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.SocketChannel; import java.nio.charset.Charset; // NIO客户端 public class NIOClient { // 客户端的多路复用器(选择器) private Selector selector; // 与服务器通信的信道 SocketChannel socketChannel; static int sendCount = 0; public NIOClient(int port)throws IOException{ selector = Selector.open(); socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("9.30.249.84",port)); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); } private void startNIOClient() { // 启动客户端读线程:读取服务器端发来的信息 new Thread(new ClientReadThread()).start(); } class ClientReadThread implements Runnable { public void run() { try { while (selector.select() > 0) { // 遍历每个有可用IO操作Channel对应的SelectionKey for (SelectionKey sk : selector.selectedKeys()) { // 如果该SelectionKey对应的Channel中有可读的数据 if (sk.isReadable()) { // 使用NIO读取Channel中的数据 SocketChannel sc = (SocketChannel) sk.channel(); ByteBuffer readBuffer = ByteBuffer.allocate(1024); sc.read(readBuffer); readBuffer.flip(); // 将字节转化为为UTF-16的字符串
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/30 15:13:28

HTR3355 I2C/SMBus IO扩展器全方位解析

在电子系统集成化、小型化的发展趋势下,GPIO端口资源紧张已成为众多硬件设计的共性难题。HTR3355作为一款专为I2C和SMBus总线设计的高性能IO扩展器,凭借其宽电压适配、灵活配置、功能完备等核心优势,能够高效弥补主控芯片IO端口不足的短板&am…

作者头像 李华
网站建设 2026/1/31 18:57:10

【完整源码+数据集+部署教程】食品包装识别系统源码分享[一条龙教学YOLOV8标注好的数据集一键训练_70+全套改进创新点发刊_Web前端展示]

一、背景意义 随着全球经济的快速发展和生活水平的提高,食品消费市场日益繁荣,食品包装的多样性和复杂性也随之增加。食品包装不仅是保护食品的物理屏障,更是传递品牌形象和消费者信息的重要载体。在这一背景下,食品包装的识别与…

作者头像 李华
网站建设 2026/1/25 22:44:40

PageHelper插件

介绍 PageHelper是第三方提供的Mybatis框架中的一款功能强大、方便易用的分页插件,支持任何形式的单标、多表的分页查询。 官网:Mybatis-PageHelper/wikis/zh/HowToUse.md at master ruiqianyi/Mybatis-PageHelper GitHub 代码实现 在pom.xml引入依…

作者头像 李华
网站建设 2026/2/2 7:40:11

苹果在日本突然“服软”,背后藏着一步大棋!

📌 目录17年封闭高墙被凿开!日本用户可自由装软件,苹果仍抽5%-21%:库克的合规躺赚套路玩疯了一、法律利剑高悬:20%营收罚款倒逼苹果妥协(一)法律硬约束:违者最高罚全年营收20%&#…

作者头像 李华