在本章中需要掌握NIO中的缓冲区的作用,并理解缓冲区中的数据处理模型,掌握Channel的作用,并结合缓冲区实现数据I/O操作,理解文件锁的作用,并且掌握字符编码处理支持类的使用,掌握Reactor设计模型,可以实现同步非则色I/O通信模型,掌握异步非阻塞I/O通信模型。
NIO(Non-blocking I/O,非阻塞I/O,或被称为NewIO)是在JDK1.4后提供的意向重要开发包-因为有了NIO的出现才使得Java底层通信的性能得到了大幅度的提升。在NIO中猜中非阻塞模式并结合通道(Channel)与缓冲区(Buffer)实现I/O通信操作,本章将讲解NIO模型及后续推出的AIO模型
提示:BIO、NIO、AIO的区别
JavaBIO:同步阻塞I/O。服务器为每一个连接的客户端分配一个线程,可以通过线程池提高线程的管理机制
javaNIO:同步阻塞I/O。服务器为每一个请求分配一个线程,所有的请求都会注册到多路复用器中,多路复用器采用轮训的形式针对每次请求创建处理线程。
javaAIO(NIO.2):异步非阻塞I/O,客户端的I/O请求都是由系统先处理,当处理完成后再通知服务器启动线程进行处理。
22.1 NIO简介
NIO提供了一个全新的底层I/O模型。与最初的java.io包中面向流(Stream Oriented)的概念不同,NIO中采用了面向缓冲区(Buffer Oriented)的概念,这样所有的数据被读取到缓冲区后,可以直接利用指针实现缓冲区的数据读取控制,同时在进行更多数据缓存时也可以保证不覆盖原始数据的前提下进行。
传统的JavaIO采用的是阻塞形式,这样当进行读或写时,该线程一直处于阻塞状态,一直到读取或写入完成前都无法进行其他任何的操作,这样在进行网络通信过程中就会因为线程阻塞而影响到程序性能,其模式如下图 在Java发展初期,由于JVM的优化性能不高,所以Java程序的运行速度很慢,此时对于I/O的性能没有过多的要求。然而随着JVM的不断优化,JVM中的字节码程序的执行性能已经接近或超过本地系统程序的处理性能,同时随着硬件技术的发展,大部分的Java程序已经不在受CPU的束缚,所以此时I/O通信的性能问题就尤为突出。在这样的背景下,Java退出了java.nio开发包,在NIO中采用可非阻塞设计模型,这样在没有数据进行读写的情况下不会产生阻塞,同时线程可以继续完成其他操作,并且一个线程可以通过选择器(Selector)同时管理多个输入输出通道。
22.2 Buffer
缓冲区(Buffer)是一个线性的、有序的数据集,一个缓冲区只能够容纳一种数据类型,Buffer类定义如下
public abstract class Buffer extends Object{}
Buffer是一个抽象类,所以提供了一个缓存操作的标准,如果要保存不同的数据类型,则应该使用Buffer的不同子类,常见的Buffer子类为ByteBuffer、CharBuffer、ShortBuffer、InBuffer、LongBuffer、FloatBuffer、DoubleBuffer在Buffer中存在一系列的状态变量,这些状态变量随着写入或读取都有可能发生改变。在缓冲区可以使用3个值表示缓冲区的状态
poison:表示下一个缓冲区读取或写入的操作指针,每箱缓冲区写入数据的时候此指针就会改变,指针永远放到写入的最后一个元素后,即如果写入了4个位置的数据,则position会执行第5个数据。
limit:表示还有多少个数据需要存储或读取,position<=limit
capacity:表示缓冲区的最大容量,limit<=capacity.此值再分配缓冲区时被设置,一般不会更改,为了进一步说明这3个指针的作用,下面通过一个具体的案例进行说明
public static void main(String[]args)
{
String str=”AAA”;//定义操作数据,长度为3
ByteBuffer buffer=ByteBuffer.allocate(20);创建缓冲区,容量为20
System.out.println(“【1】没有存放数据:capacity=”+buffer.capacity()+”limit=”+buffer.limit()+”position”+buffer.position());
buffer.put(str.getBytes());
System.out.println(“【2】保存数据:capacity=”+buffer.capacity()+”limit=”+buffer.limit()+”position”+buffer.position());
buffer.flip();
System.out.println(“【3】没有数据:capacity=”+buffer.capacity()+”limit=”+buffer.limit()+”position”+buffer.position());
while(buffer.hasRemaining())
{
System.out.println(buffer.get()+””);返回字节数据
}
System.out.println();//换行
buffer.clear();//清空缓冲区
System.out.println(“【4】清空缓冲区:capacity=”+buffer.capacity()+”limit=”+buffer.limit()+”position”+buffer.position());
}
22.3 Channel
通道(Channel可以用来读取和写入数据,通道类似于之前的输入、输出流,但是程序不会直接操作通道,所有的内容都是先读取或写入缓冲区,在通过缓冲区取得或写入。
通道与传统的流操作不同,传统的流操作分为输入流和输出流,而通道本身是双向操作的,既可以完成输入也可以玩成输出,Channel本身是一个接口标准。