AIO需要操作系统的支持,在linux内核2.6版本中加入了对真正异步IO的支持,java从jdk1.7开始支持AIO
核心类有AsynchronousSocketChannel 、AsynchronousServerSocketChannel、AsynchronousChannelGroup
前两个个类是javaAIO为TCP通信提供的异步Channel。看名字就知道应该是干什么的了。
创建AsynchronousServerSocketChannel的代码如下:
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(PORT));
其中open()有一个重载方法,可以使用指定的AsynchronousChannelGroup来创建AsynchronousServerSocketChannel。
AsynchronousChannelGroup是异步Channel的分组管理器,它可以实现资源共享。创建AsynchronousChannelGroup时,需要传入一个ExecutorService,也就是绑定一个线程池,该线程池负责两个任务:处理IO事件和触发CompletionHandler回调接口。代码如下:
AsynchronousServerSocketChannel serverSocketChannel = null; try { ExecutorService executorService = Executors.newFixedThreadPool(80); AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executorService); serverSocketChannel = AsynchronousServerSocketChannel.open(channelGroup).bind(new InetSocketAddress(9000)); }catch (IOException ioe){ ioe.printStackTrace(); }
AsynchronousServerSocketChannel创建成功后,类似于ServerSocket,也是调用accept()方法来接受来自客户端的连接,由于异步IO实际的IO操作是交给操作系统来做的,用户进程只负责通知操作系统进行IO和接受操作系统IO完成的通知。所以异步的ServerChannel调用accept()方法后,当前线程不会阻塞,程序也不知道accept()方法什么时候能够接收到客户端请求并且操作系统完成网络IO,为解决这个问题,AIO为accept方法提供两个版本:
Future<AsynchronousSocketChannel> accept() :开始接收客户端请求,如果当前线程需要进行网络IO(即获得AsynchronousSocketChannel),则应该调用该方法返回的Future对象的get()方法,但是get方法会阻塞该线程,所以这种方式是阻塞式的异步IO。
<A> void accept(A attachment ,CompletionHandler<AsynchronousSocketChannel,? super A> handler):开始接受来自客户端请求,连接成功或失败都会触发CompletionHandler对象的相应方法。其中AsynchronousSocketChannel就代表该CompletionHandler处理器在处理连接成功时的result是AsynchronousSocketChannel的实例。
而CompletionHandler接口中定义了两个方法,
completed(V result , A attachment):当IO完成时触发该方法,该方法的第一个参数代表IO操作返回的对象,第二个参数代表发起IO操作时传入的附加参数。
faild(Throwable exc, A attachment):当IO失败时触发该方法,第一个参数代表IO操作失败引发的异常或错误。
使用第一种accept方法需要如下代码
while (true){ Future<AsynchronousSocketChannel> future = serverSocketChannel.accept(); AsynchronousSocketChannel socketChannel = null; try { socketChannel = future.get(); socketChannel.write(ByteBuffer.wrap("ssss".getBytes("UTF-8"))); }catch (Exception e){ e.printStackTrace(); } }
通常使用第二种accept,实现自己的CompletionHandler实现类。
而AsynchronousSocketChannel的的用法与Socket类似,由三个方法,但是不同的是每个方法又分为Future版本与CompletionHandler版本。
connect():用于连接到指定端口,指定IP地址的服务器
read()、write():完成读写。
注意!使用异步Channel时,accept()、connect()、read()、write()等方法都不会阻塞,也就是说如果使用返回Future的这些方法,程序并不能直到什么时候成功IO,必须要使用get方法,等get方法的阻塞结束后才能确保IO完成,继续执行下面的操作。