经过前几天的学习,将BIO的基础知识总结完成,接下来今天我将总结学习NIO和AIO的知识点,在理解学习的基础上,去使用相关知识点进行编程学习。这次我将先总结NIO的知识点,再学习AIO的相关概念。
NIO
NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。
NIO是采用内存映射文件的方式处理输出输出,可以将文件或者文件的一段区域映射到内存中,然后就可以像访问内存一样来访问文件,所以进行输入输出的速度比BIO快的多。
1.Channel
Channel可以直接将文件的部分或者全部映射到 buffer中。注意不能直接访问Channel中的数据,包括 读写都不行,Channel只能与buffer进行交互。
常见方法有3个map/read/write
public class Test1 {
public static void main(String[] args) throws Exception {
File file = new File("data/Test1.java"); // 获取channel对象
FileChannel inChannel = new FileInputStream(file).getChannel(); 12345
ByteBuffer buffer = ByteBuffer.allocate(256);// 构建一个容积为256的 buffer
// 从channel中获取数据写到buffer中。文件可能大于256,所以需要进行多次读取。 可以通过-1判定读取结束
while (inChannel.read(buffer) != -1) { // 将buffer中没有数据的部分封印起来
buffer.flip(); // 设置limit,limit之后的数据不允许操作
System.out.println(buffer.limit()); //256
Charset charset = Charset.forName("UTF-8"); // 参数为编码字符集名 称,创建对应编码字符集的解码器
CharsetDecoder decoder = charset.newDecoder();//通过Charset创建对应的解码器对象
CharBuffer cb = decoder.decode(buffer);// 使用解码器可以将 ByteBuffer转换为
CharBuffer System.out.println(cb);
buffer.clear();// 清空buffer中的数据,同时将position设置为0,为下一次 读取操作做准备
}
}
}
2. Buffer(缓冲区)
Buffer主要作用就是用于转入数据,然后输出数据。最基本的实现是ByteBuffer,可以在字节数组上进行 get/set操作;另外针对基本数据类型,系统提供了7种具体的实现,例如CharBuffer、ShortBuffer、 DoubleBuffer。
3.Selector
是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel通道的状态是否处于可读、可写。如 此可以实现单线程管理多个channels也就是可以管理多个网络链接。
使用Selector的好处在于: 使用更少的线程来就可以来处理通道了, 相比使用多个线程,避免了线程上下文切换带来的开销
AIO(异步非阻塞式 )
AIO最大的一个特性就是异步能力,这种能力对socket与文件I/O都起作用。AIO其实是一种在读写操作结束之前允许进行其他操作的I/O处理。
JDK7新增了一些和文件、网络IO相关的API,AIO最大的特性就是异步处理能力,一般用于网络编程和大文件IO处理中。AIO其实就是一种在读写操作结束之前允许执行其它操作的IO处理,等读写执行完毕自动通知调用后续处理。
1.将来式异步读取:使用Future用来保存异步操作的处理结果
Path path = Paths.get("data/a1.txt"); // 从语义的角度上说比File好一些,用于封装一个文件或者文件夹对象
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
Future<Integer> future = channel.read(buffer, 0);
int readNum = future.get();
buffer.flip();
CharBuffer cb = CharBuffer.allocate(1024);
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
decoder.decode(buffer,cb,false);
cb.flip();
String ss=new String(cb.array(),0,cb.limit());
System.out.println(ss);
2.回调式异步读取:回调式是采用事件处理技术实现的
Path path = Paths.get("data/a1.txt"); // 从语义的角度上说比File好一些,用于封装一个文件或者文件夹对象
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>()
{
// 当读取完成后自动执行的方法
public void completed(Integer result, ByteBuffer attachment) {
System.out.println(Thread.currentThread().getName() + "读取数据完毕!");
}// 当读取处理过程中出错时自动执行的方法
public void failed(Throwable exc, ByteBuffer attachment) {
System.out.println(Thread.currentThread().getName() + "读取数据出现异 常:" + exc);
}
});
System.out.println("立即看到结果!");
while (true) {
System.out.println(Thread.currentThread().getName() + "sleep....");
Thread.sleep(1000);
}
BIO、NIO、AIO总结
BIO:同步阻塞,实现模式为一个连接一个线程,就是客户端连接请求时,服务器需要启动一个线程进行处理。
NIO:同步非阻塞,实现模式为一个连接一个线程,客户端发起请求时会注册到selector多路复用器上,多路复用器会轮询所有有IO请求时才启动一个线程进行处理。
AIO:异步非阻塞,一个有效请求一个线程,客户端IO请求都是由OS操作系统先完成了再通知服务器应用启动线程进行处理。
今天把NIO、AIO的相关知识点总结完成,最后又将BIO、NIO、AIO进行区别总结,流的基本知识就讲到了这里,期待更加深入的学习!同时对之前学过的知识再进行复习巩固,加强练习锻炼。加油!!!