一、I/O的划分
I/O操作可分为两步:
- 程序发出I/O请求
- 完成实际的I/O操作
针对第一步我们将I/O分为阻塞I/O(BIO)和非阻塞I/O。针对第二步,依据I/O操作是由应程序本身去执行,还是委托给操作系统去执行,然后将结果返回给应用程序,我们可以将I/O划分为同步I/O和异步I/O(AIO)。前面介绍的传统I/O、基于Channel的非阻塞I/O实际都是同步I/O。
二、同步、异步和阻塞、非阻塞的组合
三、AIO的使用
服务器端的使用
- 调用open()方法创建AsynchronousServerSocketChannel
open方法有以下两个版本:open(AsynchronousChannelGroup group)
使用指定的AsynchronousChannelGroup(分组管理器,可实现资源的共享)来创建AsynchronousServerSocketChannel。创建AsynchronousChannelGroup时需要绑定一个线程池,该线程池负责两个任务:处理IO事件和触发CompletionHandler。open()
创建一个默认的AsynchronousServerSocketChannel
- 调用bind()监听指定端口和IP
方法一:
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(PORT));
方法二:
ExecutorService executor = Executors.newFixedThreadPool(80);
AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executor);
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(channelGroup)
.bind(new InetSocketAddress(PORT));
- 调用accept()接收连接请求
由于AIO的IO操作是交由操作系统完成,IO结果应用程序不知道何时会返回结果——也就是说调用AsynchronousServerSocketChannel的accept()方法后,当前线程不会阻塞,而程序也不知道何时会受到连接请求。为了解决此问题,AIO为accept()提供以下两个版本:<A> void accept(A attachment, CompletionHandler<AsynchronousSocketChannel,? super A> handler);
接收来自客户端请求,连接成功或失败都会触发CompletionHandler对象的相应方法。其中CompletionHandler相当于一个监听器,用来监听IO操作的完成。Future<AsynchronousSocketChannel> accept()
通过Future对象的get()方法获得通道,但get方法会阻塞线程,因此该方法依然会阻塞当前线程。
客户端的使用
类似于服务端,客户端的使用也分为三步
- 利用open()方法创建一个异步Channel,open()方法的版本同样有两个
- 利用connect()方法连接到服务器
- 利用read()、write()方法进行读、写
connect()、read()、write()都有两个版本,一个需要传入CompletionHandler参数,一个返回Future对象,必须要调用Future对象的get()方法,因为只有当此方法完成时才标志只AIO操作的完成。