最近在学习Netty,然后就从 java 传统BIO到NIO然后AIO开始温习了下,目前刚刚到AIO,基于一个学习的结果,想分享下
有需要一起学习的,可以加个关注,嘻嘻
这里是阶段总结中的一部分,在我的微信公众号里,有系列博文,那里可能更全面一些,有需要的朋友,也可以搜索微信公众号“依荨”关注。谢谢
A IO ,一个异步非阻塞的IO操作,其异步相对常规的BIO和NIO的不同在哪儿呢?
以文件复制为例,传统的像这样:
基于同步IO的聊天室客户端连接服务端的TCP连接也是像这样:
简言之,类似网页前端向服务端发起的AJAX请求,这是个客户端向服务端发送的一个 “同步的Ajax请求”。
那么AIO则提供了一个“异步的Ajax请求”,怎么理解这句话?读写文件或者TCP连接总是立马返回,不会存在同步等待。
这时候,文件复制就像这样了:
聊天室的TCP连接就像这样了:
下面,以为文件复制为例,简单了解下AIO的异步非阻塞:
这里列举了AIO异步读写数据的两种方式,下面对代码做些简单的解释《以下代码行对应上述代码行》:
AIO异步读写文件方式一<java.util.concurrent. Future >,对应上述方法
copyFileAsyncChannelByFuture,即87-126行代码
87-91行:打开读写异步文件通道AsynchronousFileChannel,一个是读,一个是写
93行:分配读写缓冲区
由于这里用较大文件复制作为示例,故没有分配足够大的缓冲区来一次读写完,所以选择循环读写,循环结尾100-124行,表示当文件复制后大小相等则复制完成,退出复制循环。
100行:异步读取文件数据,这个时候,程序立马返回结果,不管是否读取完成。返回对象为java.util.concurrent.Future
102-106行:可以通过java.util.concurrent.Future#isDone判断读取是否完成,如果没有完成,这里仅仅实例打印了一行文字–可以做其他的事,即在实际应用场景中,程序可以在读取文件的同时做其他的任何事,而不是同步阻塞在这里
110行:切换读写模式,变成写
112行-117行:和读取的意义一样,不做过多解释
109行:由于循环读取,这里需要一个参数来分批读取和写入数据
java.nio.channels.AsynchronousFileChannel#read(java.nio.ByteBuffer, long )
java.nio.channels.AsynchronousFileChannel#write(java.nio.ByteBuffer, long)
上述2个方法,需要传入2个参数,
第二个参数为读/写的位置,所以119行的参数就是来记录这个位置的
120行:清空缓冲区
最后文件复制完成。
AIO异步读写文件方式二,回调方法处理,对应上述方法copyFileAsyncChannelByCompletionHandler,即31-78行代码
31-35行:打开读写异步文件通道AsynchronousFileChannel,一个是读,一个是写
36行:分配读写缓冲区
39行:定义CountDownLatch,这个是用来让 线程 等待,让其他线程执行完之后再执行的工具类,这里由于AIO读写异步操作,为了展示完整复制文件功能,所以用了这个工具,实际的项目中,除非特定情况,一般来说是不会让线程挂起的,所以这里仅仅为了这里的功能而使用
40-52行:读取文件,由于是异步的,所以在53行执行线程挂起,让读取文件操作完成后,再执行之后的代码。这里的读取文件方式,采用回调方法执行,即
java.nio.channels.CompletionHandler接口
这个接口有2个方法
java.nio.channels.CompletionHandler#completed
表示成功后执行的代码
java.nio.channels.CompletionHandler#failed
表示失败后执行的代码
这种读取方法–>
java.nio.channels.AsynchronousFileChannel#read(
java.nio.ByteBuffer,
long,
A,
java.nio.channels.CompletionHandler<java.lang.Integer,? super A>)
需要传入4个参数:缓冲区,读取起始位置,附加IO操作对象《可以为空》,回调接口
53行:线程挂起,直到其他线程结束才能执行之后的代码。这里需要等到读取结束,所以在读取成功后的45行代码,调用java.util.concurrent.CountDownLatch#countDown方法,告诉程序其他线程执行完毕<由于前面初始化CountDownLatch时,指定线程数为1,然后调用countDown减去1,则其他线程为0。即CountDownLatch只要其他线程为0时,当前线程就不再挂起了,继续执行后续程序>
54行:切换读写模式,变成写
56-68行:写入操作同读取,这里不再赘述
69行:记录读写文件位置
73-76行:复制完成,退出循环
下面,基于AIO的异步非阻塞操作,来写下基于AIO的聊天室搭建
服务端:
客户端:
对于上述代码,这里不做过多解释,每一步操作,基于前面的解释,都是可以理解的。
运行上述代码,简单的聊天室就好了: