简介
java AIO(NIO.2):异步非阻塞,服务器的实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。
适用场景
AIO方式适用于链接数目比较多且比较长的架构(重操作)比如相册服务器,充分调用OS参与并发操作,编程比较复杂,jdk7开始支持
详解
所谓AIO 异步io,主要是针对线程在调用IO获取外部数据的时候,是否阻塞调用线程来说的,一般调用步骤大致如下
- 进程向操作系统请求数据
- 操作系统将外部数据加载进内核
- 将内核的缓冲区拷贝到进程的缓冲区
- 进程获得数据完成自己的功能
AsynchronousChannel:所有AIO Channel的父类。
AsynchronousByteChannel:支持Byte读写的Channel
AsynchronousDatagramChannel:支持数据包(datagram)读写的Channel (UDP)
AsynchronousFileChannel:支持文件读写的Channel
AsynchronousServerSocketChannel:支持数据流读写的服务器端Channel
AsynchronousSocketChannel:支持数据流读写的客户端Channel
AsynchronousChannelGroup:异步Channel的分组管理,目的是为了资源共享,一个AsynchronousChannelGroup绑定一个线程池,这个线程池执行两个任务,处理IO事件和派发CompletionHandler.
AsynchronousServerSocketChannel :创建的时候可以传入一个AsynchronousChannelGroup 那么通过AsynchronousServerSocketChannel创建的AsynchronousSocketChannel 将属于同一个组,共享资源
AsynchronousChannelGroup允许绑定不同的线程池,通过三个静态方法来创建
public static AsynchronousChannelGroup withFixedThreadPool(int nThreads, ThreadFactory threadFactory)
public static AsynchronousChannelGroup withCacheThreadPool (ExecutorService executor, int initialSize)
public static AsynchronousChannelGroup withThreadPool
(ExecutorService executor)
AsynchronousChannelGroup 扮演了 Proactor的角色
Reator and Proactor
一般情况下,I/O复用机制需要事件分享器,事件分享器的作用,就是将那些读写事件源发给各个读写时间的处理者,开发者在开始的时候需要在分享器中注册感兴趣的事件,并且提供相应的处理者(event handlers) 或者是回调函数,事件分享器会在适当的时候将请求的时间分发给那些handler或者是回调函数。
涉及分享器的两种模式即为 Reactor and Proactor。
Reactor是基于同步I/O的,而Proactor模式是和异步i/o相关的,在Reactor模式中,事件分离者等待某个事件或者可应用某个操作的状态发生,(比如文件描述符可读写,或者是socket可读写) 事件分离者就把这个时间传给事先注册的事件处理函数或者是回调函数,由后者来进行实际的读写操作。
而在Proactor模式中,事件处理者直接发起一个异步读写操作(相当于请求)而实际的工作是由操作系统来工作的,发起时需要提供的参数包用于存放读到数据的缓存区.读的数据大小,或者用于存放外发数据的缓冲区 以及这个请求结束之后回调函数等信息,事件分离者得知了这个请求,它默默等待这个请求的完成,然后转发完成事件给相应的事件处理者或者是回调,
Reactor
- 某个事件处理者宣称它对某个socket上的读事件很感兴趣
- 事件分离者等着这个事件的发生
- 当事件发生了,事件分离器被唤醒,这负责通知先前那个事件处理者
- 事件处理者收到消息,于是去那个socket上读数据了. 如果需要,它再次宣称对这个socket上的读事件感兴趣,一直重复上面的步骤;
Proactor
事件处理者直接投递发一个写操作(当然,操作系统必须支持这个异步操作). 这个时候,事件处理者根本不关心读事件,它只管发这么个请求,它魂牵梦萦的是这个写操作的完成事件。这个处理者很拽,发个命令就不管具体的事情了,只等着别人(系统)帮他搞定的时候给他回个话。
事件分离者等着这个读事件的完成(比较下与Reactor的不同);
当事件分离者默默等待完成事情到来的同时,操作系统已经在一边开始干活了,它从目标读取数据,放入用户提供的缓存区中,最后通知事件分离者,这个事情我搞完了
事件分享者通知之前的事件处理者: 你吩咐的事情搞定了
事件处理者这时会发现想要读的数据已经乖乖地放在他提供的缓存区中,想怎么处理都行了。如果有需要,事件处理者还像之前一样发起另外一个写操作,和上面的几个步骤一样
对于AIO的channel jdk定义了两种类型的操作
1.Future operation(….) 通过Future判断操作是否完成
2.void Operation(Object attachment,CompletionHandler handler)
两者并无太大区别,但是不能够同时使用,建议使用CompletionHandler