最近刚刚接触AIO和NIO,对两者的IO类型(同步、异步、阻塞、非阻塞)一直很困惑,下面是自己的理解,希望各位大神能够指点一二。
Java NIO的Selector属于多路复用IO,select()方法本身是阻塞线程的,其要不停轮询其上注册的Channel,查看是否有IO就绪的Channel。之所以说其属于同步非阻塞IO的原因是,Selector并不是阻塞于等待IO就绪,所以属于非阻塞IO;其需要不停轮询Channel,并且IO就绪后需要应用程序主动从操作系统内核中读取数据,所以属于同步IO。参考代码如下:
private class ClientThread extends Thread {
@Override
public void run() {
try {
while (selector.select() > 0) {
for (SelectionKey sk : selector.selectedKeys()) {
selector.selectedKeys().remove(sk);
if (sk.isReadable()) {
SocketChannel sc = (SocketChannel) sk.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
String content = "";
while (sc.read(buffer) > 0) {
sc.read(buffer);
buffer.flip();
content += charset.decode(buffer);
}
System.out.println("聊天信息: " + content);
sk.interestOps(SelectionKey.OP_READ);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
AIO需要注册CompletionHandler事件处理器,CompletionHandler不关注IO就绪事件,而是关注IO完成事件,数据完全由操作系统内核读取到缓冲区,应用程序不需要进行实际的读写操作,所以说其属于异步IO。
sc.read(buffer, null, new CompletionHandler<Integer, Object>() {
@Override
public void completed(Integer result, Object attachment) {
buffer.flip();
String content = StandardCharsets.UTF_8.decode(buffer).toString();
//遍历每个Channel, 将收到的信息写入各Channel中
for (AsynchronousSocketChannel c : AIOServer.channelList) {
try {
c.write(ByteBuffer.wrap(content.getBytes("UTF-8"))).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
buffer.clear();
//读取下一次数据
sc.read(buffer, null, this);
}
@Override
public void failed(Throwable exc, Object attachment) {
System.out.println("读取数据失败:" + exc);
//从该Channel中读取数据失败,将该Channel删除
AIOServer.channelList.remove(sc);
}
});