文章目录
- 一、NIO介绍
- 二、NIO原理
- 三、Buffer
- 四、Channel
- 五、Selector
一、NIO介绍
NIO介绍
二、NIO原理
-
NIO有三大核心部分: 通道(Channel)、缓冲区(Buffer)和选择器(Selector)。Channel是对原I/O体系中流的模拟,可以通过Channel完成数据的读/写操作;Buffer则用于存储数据,它是NIO与普通I/O的主要区别之一;而Selector则用于监听多个Channel的状态,以实现多路复用。
-
在NIO的工作过程中,数据首先从Channel读取到Buffer中,或者从Buffer写入到Channel中。这个过程是异步的,因此不会阻塞线程。同时,Selector会不断地轮询注册的Channel,查看是否有已经就绪的I/O操作(例如读或写),如果有,就通知相应的线程进行处理。
-
Java NIO的非阻塞模式,是一个线程从某通道发送请求或者读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以知道数据变的可以读取之前,该线程可以继续做其他的事情。非阻塞写也是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
-
通俗理解:NIO是可以做到用一个线程来处理多个操作的。假设有10000个请求过来,根据实际情况,可以分配50或100个线程来处理。不像之前的阻塞 IO那样,非得分配10000个线程。
-
HTT2.0使用了多路复用的技术,做到同一个链接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。
总的来说,NIO通过非阻塞I/O操作和事件驱动机制,提高了系统的并发性能和响应速度,使得处理大量连接和I/O操作变得更加高效。因此,NIO已经被越来越多地应用到大型应用服务器中,成为解决高并发与大量连接、I/O处理问题的有效方式。
三、Buffer
Java NIO的Buffer类是一个用于特定基本数据类型的容器。它是一个对象,包含一些要写入或者要读出的数据。在NIO中,所有的数据都是用Buffer处理的。在数据读写之前,需要先放入Buffer,或者从Buffer中取出。
以下是Java NIO Buffer的基本使用步骤:
- 分配Buffer:首先,你需要通过调用allocate()方法(对于ByteBuffer,CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer,ShortBuffer等)在JVM的堆中分配一个新的Buffer。例如,以下代码分配一个新的ByteBuffer:
ByteBuffer buffer = ByteBuffer.allocate(48);
- 写入数据到Buffer:调用Buffer类的put()方法将数据写入Buffer。例如:
buffer.put((byte) 10);
buffer.put((byte) 20);
- 切换Buffer的读写模式:在写数据到Buffer后,需要调用flip()方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。换句话说,limit现在表示的是之前写进Buffer的元素的个数。现在Buffer准备好从写模式切换到读模式:
buffer.flip();
- 从Buffer中读取数据:从Buffer中读取数据,你可以使用get()方法。读取数据直到hasRemaining()返回false。这表示已经到达Buffer的末尾:
while(buffer.hasRemaining()){
byte b = buffer.get();
// do something with b
}
- 清除Buffer:当读完Buffer中的数据后,需要清除它以便下次使用。有两种方式可以清除Buffer:调用clear()或compact()方法。clear()方法会清除整个Buffer。compact()方法只会清除已经读过的数据。任何未读的数据都被移到Buffer的起始处,新写入的数据将放到Buffer的未读数据后面。
buffer.clear(); // 清除整个Buffer
或者
buffer.compact(); // 只清除已读数据
注意,在使用Buffer时,要时刻注意Buffer的容量(capacity),位置(position)和限制(limit)。容量是Buffer能够容纳的数据元素的最大数量;位置是下一个要被读或写的元素的索引;限制是第一个不应该被读或写的元素的索引。这些值可以通过调用Buffer的相应方法来获取或设置。
以上就是Java NIO Buffer的基本使用方法。通过合理地使用Buffer,你可以有效地处理大量的数据读写操作,提高程序的性能。