网络IO进行时,需要将用户态切换为内核态,操作系统内核在进行网络IO时有等待数据、拷贝数据两个阶段。
无论是阻塞IO、非阻塞IO、多路复用,都是同步IO,因为他们都是等数据准备好了,再使用当前线程去获取数据。
IO类型 | 等待数据阶段 | 拷贝数据阶段 | 用户态和内核态切换次数 |
---|---|---|---|
阻塞IO | read方法阻塞 | 阻塞 | 1次 |
非阻塞IO | 没有数据到来read方法也不会阻塞,而是返回0,有数据到来read方法则有大于0的返回值 | 阻塞 | N次(得循环向内核请求是否有数据到来) |
多路复用 | select方法阻塞,但是selector跳过了所有请求的数据等待阶段,一旦select方法解除阻塞,所有数据已经到来的channel都可以进行数据拷贝(相当于数据等待阶段是异步回调机制实现的,但是数据拷贝阶段还是阻塞进行的) | 阻塞 | 2次(一次注册selector,一次拷贝数据) |
AIO意为异步IO,即以上两个阶段都交由异步线程去处理,不能阻塞当前线程。然后在异步线程中加入一个回调函数,表示在收到数据后应该执行的操作。
(AIO很像一个异步线程的 JdbcTemplate.query(String sql, RowMapper<T> rowMapper)
,将所有拿到数据后的操作放到rowMapper中,再把这个方法放在一个异步线程或线程池中运行)
AIO的异步并不是在一次IO内部的异步,而是相对于当前线程的异步以及不同IO之间不阻塞。比如当前线程负责了所有事件的处理,发现两个客户端都需要read操作,在同步IO中,无论是哪种同步IO类型,都是在一个线程中执行,拷贝数据阶段一定有先后顺序,且一定会阻塞accept,其他客户端连都连不上;而在异步IO中,所有的操作都交由异步线程处理,read操作在异步线程中处理,不会阻塞accept事件,accept发生时,创建连接的操作也是异步线程来处理。
AIO简单示例如下:
1、文件异步IO
package net.yury.aio;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
/**
* 异步IO是指数据的等待和拷贝都交由另外一个线程执行,再给另外一个线程一个回调函数,告诉他数据准备好了就执行这个回调函数,我这边就可以得到响应。
*/
public class FileAIO {
public static void main(String[] args) {
try(AsynchronousFileChannel channel = AsynchronousFileChannel.open(Paths.get("test.txt"),StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
System.out.println("[" + Thread.currentThread().getName() + "] begin read");
channel.read(buffer, 0, null, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
buffer.flip();
System.out.println("[" + Thread.currentThread().getName() + "] file content is: " + StandardCharsets.UTF_8.decode(buffer).toString());
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
exc.printStackTrace();
}
});
System.out.println("[" + Thread.currentThread().getName() + "] finish read");
System.in.read();
}catch (IOException ex) {
ex.printStackTrace();
}
}
}
2、网络异步IO
package net.yury.aio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;
/**
* 代码还有点问题,会报错
*/
public class NetAIO {
public static void main(String[] args) throws IOException {
// 是不是很像netty的handler
CompletionHandler<Integer, ByteBuffer> handler = new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
attachment.flip();
System.out.println(StandardCharsets.UTF_8.decode(attachment).toString());
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.out.println("error1");
exc.printStackTrace();
}
};
try (AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open()) {
listener.bind(new InetSocketAddress("0.0.0.0", 8080));
listener.accept(null, new CompletionHandler<AsynchronousSocketChannel, ByteBuffer>() {
@Override
public void completed(AsynchronousSocketChannel channel, ByteBuffer attachment) {
listener.accept(null, this);
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer, buffer, handler);
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.out.println("error2");
exc.printStackTrace();
}
});
}catch (IOException ex) {
System.out.println("error3");
ex.printStackTrace();
}
System.in.read();
}
}
标签:异步,java,javaAIO,什么,线程,IO,import,ByteBuffer
From: https://www.cnblogs.com/yury757/p/17376571.html