透过现象看Java AIO的本质
2.1 我们所了解的异步
public void create() {
//TODO
}
public void build() {
executor.execute(() -> build());
}
不管是用@Async注解,还是往线程池里提交任务,他们最终都是同一个结果,就是把要执行的任务,交给另外一个线程来执行。
这个时候,可以大致的认为,所谓的“异步”,就是多线程,执行任务。
byte [] data = new byte[1024];
InputStream in = socket.getInputStream();
in.read(data);
// 接收到数据,异步处理
executor.execute(() -> handle(data));
public void handle(byte [] data) {
// TODO
}
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isReadable()) {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
executor.execute(() -> {
try {
channel.read(byteBuffer);
handle(byteBuffer);
} catch (Exception e) {
}
});
}
}
public static void handle(ByteBuffer buffer) {
// TODO
}
2.2.3 产生理解的偏差
显然BIO只能是同步,调用in.read()当前线程阻塞,有数据返回的时候,接收到数据的还是原来的线程。 而NIO也称之为同步,原因也是如此,调用channel.read()时,线程虽然不会阻塞,但读到数据的还是当前线程。
2.3 Java AIO的程序示例
2.3.1 AIO服务端程序
public class AioServer {
public static void main(String[] args) throws IOException {
System.out.println(Thread.currentThread().getName() + " AioServer start");
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open()
.bind(new InetSocketAddress("127.0.0.1", 8080));
serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
public void completed(AsynchronousSocketChannel clientChannel, Void attachment) {
System.out.println(Thread.currentThread().getName() + " client is connected");
ByteBuffer buffer = ByteBuffer.allocate(1024);
clientChannel.read(buffer, buffer, new ClientHandler());
}
public void failed(Throwable exc, Void attachment) {
System.out.println("accept fail");
}
});
System.in.read();
}
}
public class ClientHandler implements CompletionHandler<Integer, ByteBuffer> {
public void completed(Integer result, ByteBuffer buffer) {
buffer.flip();
byte [] data = new byte[buffer.remaining()];
buffer.get(data);
System.out.println(Thread.currentThread().getName() + " received:" + new String(data, StandardCharsets.UTF_8));
}
public void failed(Throwable exc, ByteBuffer buffer) {
}
}
2.3.2 AIO客户端程序
public class AioClient {
public static void main(String[] args) throws Exception {
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
channel.connect(new InetSocketAddress("127.0.0.1", 8080));
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("Java AIO".getBytes(StandardCharsets.UTF_8));
buffer.flip();
Thread.sleep(1000L);
channel.write(buffer);
}
}
2.3.3 异步的定义猜想结论
3.1 问题1:执行completed()方法的这个线程是谁创建的,什么时候创建的
3.2 问题2:AIO注册事件监听和执行回调是如何实现的
3.2.1 1、注册事件
3.2.2 2、监听事件
3.2.3 3、处理事件
3.2.4 核心流程总结
3.3 问题3: 监听回调的本质是什么?
3.3.1 系统调用与函数调用
3.3.2 用户态和内核态之间的通信
3.3.3 用实际例子验证结论
1、由于内核态无法直接调用用户态函数,Java AIO的本质,就是只在用户态实现异步。并没有达到理想意义上的异步。
理想中的异步
A在网上购物时,填好家庭地址付款提交订单,这个相当于注册监听事件 商家发货,B把东西送到A家门口,这个相当于回调。
现实中的异步
此时,A下单并跟D打招呼,相当于注册事件。在AIO中就是EPoll.ctl(...)注册事件。 保安在门口蹲着相当于监听事件,在AIO中就是Thread-0线程,做EPoll.wait(..) 快递员把电视送到门口,相当于有IO事件到达。 保安通知C电视到了,C过来搬电视,相当于处理事件。在AIO中就是Thread-0往任务队列提交任务,Thread-1 ~n去取数据,并执行回调方法。
*文/Inspire
END
这里有最新开源资讯、软件更新、技术干货等内容
点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦
微信扫码关注该文公众号作者
戳这里提交新闻线索和高质量文章给我们。
来源: qq
点击查看作者最近其他文章