日期:
来源:OSC开源社区收集编辑:Inspire
1
前言
2
什么是异步
2.1 我们所了解的异步
@Asyncpublic 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>() {@Overridepublic 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());}@Overridepublic void failed(Throwable exc, Void attachment) {System.out.println("accept fail");}});System.in.read();}}public class ClientHandler implements CompletionHandler<Integer, ByteBuffer> {@Overridepublic 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));}@Overridepublic 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
AIO示例引发思考的问题
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 用实际例子验证结论
4
Java AIO的本质是什么?
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
这里有最新开源资讯、软件更新、技术干货等内容
点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦