Java NIO(非阻塞IO)简介

embedded/2024/11/11 23:48:10/

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.ppmy.cn/embedded/115071.html

相关文章

C++之文件操作

文件分类 文本文件&#xff1a;以 ASCII码 存储 二进制文件&#xff1a;以 二进制 形式存储 操作文件: 1. ofstream&#xff1a;写操作 2. ifstream&#xff1a; 读操作 3. fstream &#xff1a; 读写操作 写文件 1. 包含头文件 #include <fstream> 2. 创建流对象 o…

JVM 调优篇7 调优案例4- 线程溢出

一 线程溢出 1.1 报错信息 每个 Java 线程都需要占用一定的内存空间&#xff0c;当 JVM 向底层操作系统请求创建一个新的 native 线程时&#xff0c;如果没有足够的资源分配就会报此类错误。报错信息&#xff1a;java.lang.outofmemoryError:unable to create new Native Thr…

鸿蒙Harmony应用开发,数据驾驶舱页面的实现

先来看看我们要实现的驾驶舱的页面是什么样的 对于这种 响应式布局的页面构建&#xff0c;我们的脑子里面要有一个概念&#xff0c;就是"分而治之"。我们把这个页面进行分割&#xff0c;分割成不同的块然后再来逐个实现. 不难发现&#xff0c;我们可以将这个看到的效…

【hot100-java】【组合总和】

R8-回溯篇 印象题&#xff0c;很基本的回溯 class Solution {void backtrack(List<Integer> state,int target,int[] choices,int start,List<List<Integer>> ret){//子集和等于target&#xff0c;记录解if (target0){ret.add(new ArrayList<>(state)…

未来视界,触手可及:bigmp4 引领 AI 视频处理新革命

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;技术已经渗透到我们生活的方方面面&#xff0c;从智能助手到自动驾驶&#xff0c;AI 正在改变着世界。而在视频处理领域&#xff0c;bigmp4 的横空出世&#xff0c;无疑为视频爱好者和专业人士带来了一场革命…

LabVIEW提高开发效率技巧----采用并行任务提高性能

在复杂的LabVIEW开发项目中&#xff0c;合理利用并行任务可以显著提高系统的整体性能和响应速度。并行编程是一种强大的技术手段&#xff0c;尤其适用于实时控制、数据采集以及多任务处理等场景。LabVIEW的数据流编程模型天然支持并行任务的执行&#xff0c;结合多核处理器的硬…

Python办公自动化案例(四):将Excel数据批量保存到Word表格中

案例:将excel数据批量保存到Word表格中 要将Excel数据批量保存到Word表格中,可以使用Python的openpyxl库来读取Excel文件,以及python-docx库来创建和编辑Word文档。以下是一段示例代码,以及代码解释和一些注意事项。 准备好的Excel数据: 1.安装所需库 首先,确保你已经…

/etc/sudoers文件中的哪些配置会影响系统安全?

/etc/sudoers 文件中的配置对系统安全有很大影响 用户权限配置&#xff1a;允许哪些用户使用 sudo 执行特权命令。如果配置不当&#xff0c;可能导致未经授权的用户获得管理员权限。 例如&#xff1a; root ALL(ALL:ALL) ALL %admin ALL(ALL) ALL %sudo ALL(ALL:ALL) ALL…