Java NIO
1. 简介
Java NIO(New I/O)是Java提供的一种非阻塞I/O操作的机制,引入了一些新的核心概念,如通道(Channel)、缓冲区(Buffer)和选择器(Selector)。相比传统的阻塞I/O操作,Java NIO能够提供更高的性能和可扩展性。
2. 基本概念
在开始使用Java NIO进行开发之前,我们需要了解以下三个基本概念:通道(Channel)、缓冲区(Buffer)和选择器(Selector)。
通道(Channel)
通道是Java NIO中的基本概念之一,代表着一个连接到实体如文件、套接字等的开放连接。可以通过通道读取和写入数据。Java NIO提供了不同类型的通道,如文件通道(FileChannel)和网络通道(SocketChannel、ServerSocketChannel等)。
缓冲区(Buffer)
缓冲区是一个对象,用于存储数据。在Java NIO中,所有数据都通过缓冲区进行传输。缓冲区实际上是一个数组,可以存储特定类型的数据。它提供了对数据的结构化访问和操作。
选择器(Selector)
选择器是Java NIO中的一个组件,用于监听多个通道的事件(如连接、读、写等事件)。通过选择器,可以实现单个线程同时处理多个通道的I/O操作。
3. NIO核心组件
Java NIO的核心组件包括通道(Channel)、缓冲区(Buffer)和选择器(Selector)。下面将对这些组件进行详细介绍。
通道(Channel)
通道是Java NIO中的一个抽象概念,表示与实体之间的连接。它可以用于读取和写入数据。Java NIO提供了以下类型的通道:
FileChannel:用于对文件进行读写操作。
SocketChannel:用于通过TCP进行网络套接字的读写操作。
ServerSocketChannel:用于监听传入的TCP连接请求。
DatagramChannel:用于通过UDP进行网络套接字的读写操作。
缓冲区(Buffer)
缓冲区是一个对象,用于存储数据。它是一个数组,可以存储特定类型的数据。缓冲区提供了对数据的结构化访问和操作。在Java NIO中,主要有以下类型的缓冲区:
ByteBuffer:用于存储字节数据。
CharBuffer:用于存储字符数据。
ShortBuffer:用于存储短整型数据。
IntBuffer:用于存储整型数据。
LongBuffer:用于存储长整型数据。
FloatBuffer:用于存储浮点型数据。
DoubleBuffer:用于存储双精度浮点型数据。
Buffer详解
Buffer就是一个数组缓冲池。Buffer有两种模式,往Buffer中写数据,或者从Buffer中读取数据。读写模式通过flip()函数切换。
Buffer默认为写模式
Buffer主要通过三个变量和一个切换函数flip()来维护。
1、position 当前第一个可以读或者写的下标
2、limit 当前可读或者可写的最后一位下标+1
3、capacity Buffer的容量,也就是数组长度。
4、flip() flip()用来切换读写模式。
当从写切换读之后,position和limit之间的数据是之前写的数据,可以进行读取。 当从读切换写之后,postion和limit之间才可以被写数据。
public final Buffer flip() {
limit = position;
position = 0;
return this;
}
主要方法
get(): 读取一个byte,将position++
get(byte[] bytes,int offeset,int length): 将buffer中的[offset,offset+length)复制到bytes中,position+=length
put(byte[] bytes): 往buffer中写入bytes,position += bytes.length
clear(): 将buffer清除,position=0,limit=capacity
compact(): 假设还有n个字节未被读取,就将这n个字节搬运到数组头部,从数组的第n位开始写
remaining(): 返回limit - position,也就是当前还是多少字节未读取或者未写
选择器(Selector)
选择器是Java NIO中的一个组件,用于监听多个通道的事件。通过选择器,可以实现单个线程同时处理多个通道的I/O操作。选择器提供了一个高效的事件驱动机制,可以显著减少线程的数量。它的主要方法包括:
open():打开一个选择器。
select():选择已经准备就绪的通道。
selectNow():非阻塞地选择已经准备就绪的通道。
register():注册通道到选择器,并指定感兴趣的事件。
cancel():取消通道的注册。
4. NIO的使用示例
下面将通过一个简单的示例来演示如何使用Java NIO进行开发。
创建通道(Channel)
首先,我们需要创建一个通道来进行数据的读取和写入。以下示例演示如何创建一个文件通道(FileChannel):
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
public class ChannelExample {
public static void main(String[] args) throws Exception {
// 创建一个文件通道
RandomAccessFile file = new RandomAccessFile("data.txt", "rw");
FileChannel channel = file.getChannel();
// 使用通道进行读写操作
// ...
// 关闭通道
channel.close();
}
}
使用缓冲区(Buffer)
一旦创建了通道,我们可以使用缓冲区来进行数据的读取和写入操作。以下示例演示如何使用ByteBuffer进行数据的读取和写入:
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class BufferExample {
public static void main(String[] args) throws Exception {
// 创建一个文件通道
RandomAccessFile file = new RandomAccessFile("data.txt", "rw");
FileChannel channel = file.getChannel();
// 创建一个缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 从通道读取数据到缓冲区
int bytesRead = channel.read(buffer);
// 从缓冲区写入数据到通道
int bytesWritten = channel.write(buffer);
// 清空缓冲区
buffer.clear();
// 关闭通道
channel.close();
}
}
使用选择器(Selector)
选择器可以用于同时监听多个通道的事件。以下示例演示如何使用选择器:
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
public class SelectorExample {
public static void main(String[] args) throws Exception {
// 创建一个选择器
Selector selector = Selector.open();
// 创建一个服务器套接字通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 注册通道到选择器,并指定感兴趣的事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
// 监听选择器上的事件
while (true) {
int readyChannels = selector.select();
// 处理已经准备就绪的通道
// ...
}
// 关闭选择器
selector.close();
}
}
- 感谢你赐予我前进的力量