AIO是什么?
AIO是Java7出来的新东西,是对原有NIO的一种补充,
前面写到的内容已经和NIO,BIO比较过:Java Netty 学习(三)- BIO,AIO,NIO深入浅出
AIO介绍
在NIO编程时,会用到Selector,就是轮询,从而判断哪个channel可以使用。
而在AIO编程中,并不会用到Selector,它的可伸缩性更好,当有相应事件时,由系统调用提醒,可以理解为回调函数,从而Java程序员只需要把一些事件代码写好就可以了。
再打个比方,或许都用过ajax,以及用过jquery的$.post,记得这个方法都会有好几个方法,通过调用返回的状态来确定的。
AIO也是这样。
AIO中,主要有4个比较重要的异步类:
- AsynchronousSocketChannel
- AsynchronousServerSocketChannel
- AsynchronousFileChannel
- AsynchronousByteChannel
CompletionHandler接口
这个接口就两个方法,成功和失败,可以用于connect,read,write,accept等:
public interface CompletionHandler<V,A> {
//调用成功
void completed(V result, A attachment);
//调用失败
void failed(Throwable exc, A attachment);
}
例子
看个AsynchronousSocketChannel和AsynchronousServerSocketChannel的例子,助于理解:
AIOServer:
public class AIOServer {
private AsynchronousServerSocketChannel server ;
private Object attachment;
public AIOServer(){
try {
server = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress("127.0.0.1", 8088));
System.out.println("server run at:127.0.0.1:8088");
} catch (IOException e) {
e.printStackTrace();
}
server.accept(attachment, new CompletionHandler<AsynchronousSocketChannel, Object>() {
final ByteBuffer buffer = ByteBuffer.allocate(1024);
Future<Integer> writeResult = null; //定义一个异步任务,用于检验回写
@Override
public void completed(AsynchronousSocketChannel channel, Object attachment) {
try {
//代表成功拿到了一个
buffer.clear();
channel.read(buffer).get(100, TimeUnit.SECONDS); //把result里面东西,读到buffer里面。有超时的读取。
System.out.println("server read the data from client: " + new String(buffer.array()));
buffer.flip();
writeResult = channel.write(buffer);
} catch (Exception e) {
e.printStackTrace();
} finally{
server.accept(null, this); //需要加上这一句,否则只会相应一次?
try {
System.out.println("server write data's length" + writeResult.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
@Override
public void failed(Throwable exc, Object attachment) {
System.out.println("server accept failed");
}
});
}
public static void main(String[] args) {
new AIOServer();
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
客户端AIOClient:
public class AIOClient {
private AsynchronousSocketChannel channel;
private InetSocketAddress serverAddress = new InetSocketAddress("127.0.0.1", 8088);
private final ByteBuffer buffer = ByteBuffer.allocate(1024);
public AIOClient() {
try {
channel = AsynchronousSocketChannel.open();
} catch (IOException e) {
e.printStackTrace();
}
}
private class ConnectCompletionHandler implements CompletionHandler<Void, Object> {
AsynchronousSocketChannel channel;
public ConnectCompletionHandler(AsynchronousSocketChannel channel) {
this.channel = channel;
}
@Override
public void completed(Void result, Object attachment) {
System.out.println("connect server successfully");
ByteBuffer bf = ByteBuffer.wrap("this is from client".getBytes());
channel.write(bf, bf, new WriteCompletionHandler(channel));
channel.read(buffer, null, new ReadCompletionHandler(channel));
}
@Override
public void failed(Throwable exc, Object attachment) {
System.out.println("connect server failed");
}
}
private class WriteCompletionHandler implements CompletionHandler<Integer, ByteBuffer> {
AsynchronousSocketChannel channel;
public WriteCompletionHandler(AsynchronousSocketChannel channel) {
this.channel = channel;
}
@Override
public void completed(Integer result, ByteBuffer attachment) {
if (attachment.hasRemaining()) { // 有剩余,就一致写。
channel.write(attachment, attachment, this);
}
System.out.println("write successfully");
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.out.println("write failed");
}
}
private class ReadCompletionHandler implements CompletionHandler<Integer, Object> {
AsynchronousSocketChannel channel;
public ReadCompletionHandler(AsynchronousSocketChannel channel) {
this.channel = channel;
}
@Override
public void completed(Integer result, Object attachment) {
buffer.flip();
System.out.println("read successfully,and data is :" + buffer.array());
}
@Override
public void failed(Throwable exc, Object attachment) {
System.out.println("read failed");
}
}
private void bind() {
channel.connect(serverAddress, null, new ConnectCompletionHandler(this.channel));
}
public static void main(String[] args) {
new AIOClient().bind();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
整体思路,类似于注册,注册一个回调方法,当有socket连接时候,就会自动调用方法,需要注意以下几个点:
1. AsynchronousServerChannel的accept方法:
public abstract <A> void accept(A attachment,CompletionHandler<AsynchronousSocketChannel,? super A> handler);
它的CompletionHandler
第二个参数是AsynchronousSocketChannel,第一个是Object。
- 由于具有延迟,所以AsynchronousServerChannel的read和write方法,返回类型都是:
Future<Integer>
,也就是你可以利用返回值去查询写了多少数据。 - 而AsynchronousSocketChannel的read和write方法,需要用CompletionHandler时,返回的结果参数都是Integer,而不是直接的传递数据结果。