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

Java NIO(非阻塞IO)简介

Java NIO(非阻塞IO)是一种用于高效处理大量并发连接的新式IO操作方式。与传统的阻塞IO相比,NIO提供了更高的性能和更好的并发能力。Java NIO主要包括三个核心组件:BufferChannelSelector。下面将详细介绍这些组件及其基本使用方法。

Java NIO概述

Java NIO(New IO)自Java 1.4版本引入,后来在Java 7中得到了进一步增强。NIO的主要目的是解决传统阻塞IO在处理大量并发连接时的性能瓶颈。NIO采用了一种基于事件驱动和多路复用的模型,允许应用程序在单个线程上处理多个连接。

核心组件

Java NIO的核心组件包括:

  1. Buffer:缓冲区,用于存储数据。
  2. Channel:通道,用于读写数据。
  3. Selector:选择器,用于监控多个通道的状态。

1. Buffer(缓冲区)

Buffer是NIO中的基本数据结构,用于存储数据。在NIO中,所有数据都必须先读入Buffer,然后再从Buffer写入目标。Buffer具有以下特点:

  • 容量(Capacity)Buffer的最大容量。
  • 位置(Position):当前读写的位置。
  • 限制(Limit):当前读写操作的结束位置。

常见的Buffer类型包括:

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

2. Channel(通道)

Channel是NIO中的另一个核心组件,用于连接源和目的地,实现数据的读写操作。常见的Channel类型包括:

  • FileChannel:用于文件读写。
  • SocketChannel:用于网络通信。
  • ServerSocketChannel:用于监听网络连接。

Channel支持以下操作:

  • read():从通道读取数据到Buffer
  • write():从Buffer写入数据到通道。
  • close():关闭通道。

3. Selector(选择器)

Selector用于监控多个Channel的状态,可以同时监控多个Channel的读写状态。常见的Selector操作包括:

  • open():打开选择器。
  • register():注册Channel到选择器。
  • select():选择已准备好的Channel
  • selectedKeys():获取已选择的Channel集合。

示例代码

下面通过几个示例代码展示如何使用Java NIO进行基本的读写操作。

示例1:使用BufferChannel读写文件
1import java.io.FileInputStream;
2import java.io.FileOutputStream;
3import java.nio.ByteBuffer;
4import java.nio.channels.FileChannel;
5
6public class FileCopyExample {
7    public static void main(String[] args) {
8        try (
9            FileInputStream in = new FileInputStream("input.txt");
10            FileOutputStream out = new FileOutputStream("output.txt")
11        ) {
12            // 创建Buffer
13            ByteBuffer buffer = ByteBuffer.allocate(1024);
14
15            // 获取FileChannel
16            FileChannel inputChannel = in.getChannel();
17            FileChannel outputChannel = out.getChannel();
18
19            // 循环读取数据
20            while (inputChannel.read(buffer) > 0) {
21                // 切换为读模式
22                buffer.flip();
23
24                // 将数据写入输出通道
25                outputChannel.write(buffer);
26
27                // 清空Buffer
28                buffer.clear();
29            }
30
31            // 关闭通道
32            inputChannel.close();
33            outputChannel.close();
34        } catch (Exception e) {
35            e.printStackTrace();
36        }
37    }
38}
示例2:使用SocketChannel进行网络通信
1import java.io.IOException;
2import java.net.InetSocketAddress;
3import java.nio.ByteBuffer;
4import java.nio.channels.SocketChannel;
5
6public class ClientExample {
7    public static void main(String[] args) {
8        try (
9            SocketChannel socketChannel = SocketChannel.open()
10        ) {
11            // 连接到服务器
12            socketChannel.connect(new InetSocketAddress("localhost", 9999));
13
14            // 创建Buffer
15            ByteBuffer buffer = ByteBuffer.allocate(1024);
16
17            // 写入数据
18            buffer.put("Hello, server!".getBytes());
19            buffer.flip();
20            socketChannel.write(buffer);
21
22            // 读取响应
23            buffer.clear();
24            socketChannel.read(buffer);
25            buffer.flip();
26            byte[] response = new byte[buffer.remaining()];
27            buffer.get(response);
28            System.out.println("Received from server: " + new String(response));
29
30            // 关闭通道
31            socketChannel.close();
32        } catch (IOException e) {
33            e.printStackTrace();
34        }
35    }
36}
示例3:使用ServerSocketChannelSelector监听网络连接
1import java.io.IOException;
2import java.net.InetSocketAddress;
3import java.nio.ByteBuffer;
4import java.nio.channels.SelectionKey;
5import java.nio.channels.Selector;
6import java.nio.channels.ServerSocketChannel;
7import java.nio.channels.SocketChannel;
8import java.util.Iterator;
9import java.util.Set;
10
11public class ServerExample {
12    public static void main(String[] args) {
13        try (
14            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
15            Selector selector = Selector.open()
16        ) {
17            // 绑定端口
18            serverSocketChannel.socket().bind(new InetSocketAddress(9999));
19            serverSocketChannel.configureBlocking(false);
20
21            // 注册选择器
22            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
23
24            while (true) {
25                selector.select();
26
27                Set<SelectionKey> selectedKeys = selector.selectedKeys();
28                Iterator<SelectionKey> iterator = selectedKeys.iterator();
29
30                while (iterator.hasNext()) {
31                    SelectionKey key = iterator.next();
32
33                    if (key.isAcceptable()) {
34                        // 处理新连接
35                        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
36                        SocketChannel socketChannel = ssc.accept();
37                        socketChannel.configureBlocking(false);
38                        socketChannel.register(selector, SelectionKey.OP_READ);
39                    } else if (key.isReadable()) {
40                        // 读取数据
41                        SocketChannel socketChannel = (SocketChannel) key.channel();
42                        ByteBuffer buffer = ByteBuffer.allocate(1024);
43
44                        int bytesRead = socketChannel.read(buffer);
45                        if (bytesRead == -1) {
46                            socketChannel.close();
47                        } else {
48                            buffer.flip();
49                            byte[] data = new byte[buffer.remaining()];
50                            buffer.get(data);
51                            System.out.println("Received from client: " + new String(data));
52
53                            // 回应客户端
54                            buffer.clear();
55                            buffer.put(("Echo: " + new String(data)).getBytes());
56                            buffer.flip();
57                            socketChannel.write(buffer);
58                        }
59                    }
60
61                    iterator.remove();
62                }
63            }
64        } catch (IOException e) {
65            e.printStackTrace();
66        }
67    }
68}

总结

Java NIO通过BufferChannelSelector这三个核心组件,提供了高效的非阻塞IO操作。相比于传统的阻塞IO,NIO能够更好地处理大量并发连接,提高了系统的吞吐量和响应速度。通过上述示例代码,我们可以看到如何使用Java NIO进行基本的读写操作和网络通信。

掌握Java NIO的基本概念和使用方法后,开发者可以进一步探索更高级的NIO特性,如异步文件通道(AsynchronousFileChannel)、异步套接字通道(AsynchronousSocketChannel)等,以实现更加复杂的网络编程需求。


http://www.kler.cn/a/313014.html

相关文章:

  • linux部分问题以及解决方式
  • b4tman / docker-squid 可快速安装运行的、容器型代理服务器 + podman
  • C语言 | Leetcode C语言题解之第543题二叉树的直径
  • 周末适合做一些总结性的工作,不适合开启新的探索性的任务
  • CAD 图元 动一下消失
  • 【设计模式系列】享元模式(十五)
  • 【秋招笔试-支持在线评测】8.28华为秋招(已改编)-三语言题解
  • 算法打卡 Day34(贪心算法)-分发饼干 + 摆动序列 + 最大子序和
  • 《粮油与饲料科技》是什么级别的期刊?是正规期刊吗?能评职称吗?
  • 【设计模式-桥接】
  • Visual Studio 引入外部静态库与动态库
  • 【双语新闻】AGI安全与对齐,DeepMind近期工作
  • Instagram全面升级“青少年账号”保护措施,除了信息分类过滤,还应从根源加强内容审核
  • 八、explicit关键字在C++中的用法
  • 【第十三章:Sentosa_DSML社区版-机器学习聚类】
  • dedecms——四种webshell姿势
  • 2024年“华为杯”研赛第二十一届中国研究生数学建模竞赛解题思路|完整代码论文集合
  • DataX--Web:图形化界面简化大数据任务管理
  • 开发易忽视的问题:InnoDB 行锁设计与实现
  • Pycharm中虚拟环境依赖路径修改
  • LeetCode 面试经典150题 67.二进制求和
  • istio中使用serviceentry结合egressgateway实现多版本路由
  • JFinal整合Websocket
  • 大模型中常见 loss 函数
  • 关于“华为杯”第二十一届中国研究生数学建模竞赛赛题下载及提交作品的重要提醒
  • pytorch实现RNN网络