NIO学习(一)

[size=medium][size=medium][b]NIO学习[/b][/size]

一.NIO中的几个基础概念

在NIO中有几个比较关键的概念:Channel(通道),Buffer(缓冲区),Selector(选择器)。
  首先从Channel说起吧,通道,顾名思义,就是通向什么的道路,为某个提供了渠道。在传统IO中,我们要读取一个文件中的内容,通常是像下面这样读取的:
public class Test {
public static void main(String[] args) throws IOException {
File file = new File("data.txt");
InputStream inputStream = new FileInputStream(file);
byte[] bytes = new byte[1024];
inputStream.read(bytes);
inputStream.close();
}
}
  这里的InputStream实际上就是为读取文件提供一个通道的。
  因此可以将NIO 中的Channel同传统IO中的Stream来类比,但是要注意,传统IO中,Stream是单向的,比如InputStream只能进行读取操作,OutputStream只能进行写操作。而Channel是双向的,既可用来进行读操作,又可用来进行写操作。
  Buffer(缓冲区),是NIO中非常重要的一个东西,在NIO中所有数据的读和写都离不开Buffer。比如上面的一段代码中,读取的数据时放在byte数组当中,而在NIO中,读取的数据只能放在Buffer中。同样地,写入数据也是先写入到Buffer中。
下面介绍一下NIO中最核心的一个东西:Selector。可以说它是NIO中最关键的一个部分,Selector的作用就是用来轮询每个注册的Channel,一旦发现Channel有注册的事件发生,便获取事件然后进行处理。
比如看下面的这个例子:

[img]http://images.cnitblog.com/i/288799/201408/181105032681855.jpg[/img]

用单线程处理一个Selector,然后通过Selector.select()方法来获取到达事件,在获取了到达事件之后,就可以逐个地对这些事件进行响应处理。


二.Channel

在前面已经提到,Channel和传统IO中的Stream很相似。虽然很相似,但是有很大的区别,主要区别为:通道是双向的,通过一个Channel既可以进行读,也可以进行写;而Stream只能进行单向操作,通过一个Stream只能进行读或者写;
  以下是常用的几种通道:
FileChannel
SocketChanel
ServerSocketChannel
DatagramChannel
  通过使用FileChannel可以从文件读或者向文件写入数据;通过SocketChannel,以TCP来向网络连接的两端读写数据;通过ServerSocketChanel能够监听客户端发起的TCP连接,并为每个TCP连接创建一个新的SocketChannel来进行数据读写;通过DatagramChannel,以UDP协议来向网络连接的两端读写数据。
  下面给出通过FileChannel来向文件中写入数据的一个例子:

public class Test {
public static void main(String[] args) throws IOException {
File file = new File("data.txt");
FileOutputStream outputStream = new FileOutputStream(file);
FileChannel channel = outputStream.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
String string = "java nio";
buffer.put(string.getBytes());
buffer.flip(); //此处必须要调用buffer的flip方法
channel.write(buffer);
channel.close();
outputStream.close();
}
}
  通过上面的程序会向工程目录下的data.txt文件写入字符串"java nio",注意在调用channel的write方法之前必须调用buffer的flip方法,否则无法正确写入内容,至于具体原因将在下篇博文中具体讲述Buffer的用法时阐述。


三.Buffer

Buffer,故名思意,缓冲区,实际上是一个容器,是一个连续数组。Channel提供从文件、网络读取数据的渠道,但是读取或写入的数据都必须经由Buffer。具体看下面这张图就理解了:

[img]http://images.cnitblog.com/i/288799/201408/181521285655283.jpg[/img]

  上面的图描述了从一个客户端向服务端发送数据,然后服务端接收数据的过程。客户端发送数据时,必须先将数据存入Buffer中,然后将Buffer中的内容写入通道。服务端这边接收数据必须通过Channel将数据读入到Buffer中,然后再从Buffer中取出数据来处理。
  在NIO中,Buffer是一个顶层父类,它是一个抽象类,常用的Buffer的子类有:
ByteBuffer
IntBuffer
CharBuffer
LongBuffer
DoubleBuffer
FloatBuffer
ShortBuffer
  如果是对于文件读写,上面几种Buffer都可能会用到。但是对于网络读写来说,用的最多的是ByteBuffer。
  关于Buffer的具体使用以及它的limit、posiion和capacity这几个属性的理解在下一篇文章中讲述。


四.Selector


Selector类是NIO的核心类,Selector能够检测多个注册的通道上是否有事件发生,如果有事件发生,便获取事件然后针对每个事件进行相应的响应处理。这样一来,只是用一个单线程就可以管理多个通道,也就是管理多个连接。这样使得只有在连接真正有读写事件发生时,才会调用函数来进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程,并且避免了多线程之间的上下文切换导致的开销。
  与Selector有关的一个关键类是SelectionKey,一个SelectionKey表示一个到达的事件,这2个类构成了服务端处理业务的关键逻辑。[/size]
### Java NIO学习资源与教程 Java NIO种高效的输入/输出模型,自 Java 1.4 版本引入以来,广泛应用于高性能网络编程场景。以下是关于 Java NIO 的核心概念及其学习路径。 #### 核心概念概述 Java NIO 提供了种不同于传统 IO 的操作模式,主要基于 **Channels 和 Buffers** 进行数据传输和存储[^1]。它支持非阻塞 I/O 操作以及多路复用技术,使得单线程能够高效管理多个连接。具体实现上,`Selector` 被用来监听多个 `Channel` 上的事件,例如读写请求[^3]。 #### 初学者的学习建议 对于初学者来说,可以从以下几个方面入手: 1. **理解基础组件** - 学习如何使用 Buffer 类型(ByteBuffer, CharBuffer 等),掌握其基本方法如 flip()、clear() 和 compact()。 - 掌握 Channel 的功能及其实现类(FileChannel, SocketChannel 等)。 2. **熟悉 Selector 工作机制** - 阅读并实践 Selector 如何注册到不同类型的 Channel 中,并设置感兴趣的事件集合(如 OP_READ 或 OP_WRITE)。例如: ```java int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; ``` 3. **Reactor 模式的应用** - 理解 Reactor 设计模式的核心思想——即利用单或少量线程来处理大量并发连接。这通常涉及 Selector 对多个 Channel 的轮询监控。 #### 推荐书籍与在线课程 - **《Java NIO》 by Ron Hitchens**: 此书深入讲解了 NIO 的内部结构及其实际应用场景。 - Oracle 官方文档: https://docs.oracle.com/javase/tutorial/essential/io/ - Coursera 平台上的高级 Java 编程课程也涵盖了相关内容。 #### 示例代码展示 下面给出段简单的服务器端程序片段,演示了如何创建 ServerSocketChannel 并将其配置为非阻塞模式后再绑定至某个地址端口上: ```java ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); InetSocketAddress address = new InetSocketAddress(8080); serverSocketChannel.bind(address); // 创建 selector 来跟踪 channel 的状态变化 Selector selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值