Introduction to AIO model
AIO (Asynchronous I/O) asynchronous non blocking model supports AIO since java jdk.17. The AIO model needs the support of the operating system. The biggest feature of AIO is asynchronous capability, which works on socket and I/O.
Different from the NIO model, a read-write operation is taken as an example, just call the read and write API s directly. For read operation: when there is a stream readable, the system will spread the readable into the buffer of the read method and notify the application. Reading and writing are asynchronous, and the callback function will be actively called after completion.
In JDK 1.7, aio is also called nio.2.0. Four asynchronous channels are added under the java.nio.channels package:
- AsynchronousSocketChannel: asynchronous operation TCP channel, mainly connected to AsynchronousServerSocketChannel, which is generally implemented on the client;
- Asynchronous Server socketchannel: asynchronous operation of TCP channel, which mainly receives the connection of the client and is generally implemented on the server;
- Asynchronous filechannel: operation file;
- Asynchronous datagram Chanel: channel for asynchronous operation of UDP.
Asynchronous Server socketchannel: the socket of the network communication server in AIO
AIO implementation method, take accept method as an example.
Because the actual IO operation of asynchronous IO is entrusted to the operating system, and the application program is only responsible for notifying the operating system of IO and the interface operating system of IO completion, the asynchronous accept method call will not be blocked.
Asynchronous IO can be implemented in two ways:
1. future method
Future<AsynchronousSocketChannel> accept();
Submit an IO operation request (Accept/read/write) and return to the future to check the future. The future.get() method will block the user program until the operation is completed normally. It is relatively simple to use the future method, but the future.get() is synchronous. It is easy to enter the synchronous programming mode. This method will make the asynchronous operation of AIO a device.
2. Callback callback method
<A> void accept(A attachment, CompletionHandler<AsynchronousSocketChannel,? super A> handler)
Start receiving the connection from the client. The successful or failed connection is the response method that triggers the CompletionHandler object.
The CompletionHandler interface provides two methods:
void completed(V result, A attachment);
The method is triggered when IO is completed. The first parameter of the method represents the returned object of IO operation, and the second parameter represents the additional parameters passed in when initiating IO operation.
void failed(Throwable exc, A attachment);
This method is triggered when IO fails. The first parameter represents the exception or error caused by the failure of IO operation, and the second parameter represents the additional parameters passed in when initiating IO operation.
That is, submit an IO operation request (Accept/read/write), specify a CompletionHandler, and send a notification when the asynchronous IO operation is completed. At this time, the completed or failed methods of the CompletionHandler object will be called.
The implementation of AIO needs to fully call the operating system parameters, IO needs the support of the operating system, and concurrency also needs the support of the operating system, so the differences between different operating systems in performance will be obvious.
AIO callback programming
AIO server (Server.java):
/** * AIO Server code * @Author : quwenjing * @Date : 2021/11/18 19:01 **/ public class Server { public static void main(String[] args) { try { //Create server channel AsynchronousServerSocketChannel asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open(); //Binding port asynchronousServerSocketChannel.bind(new InetSocketAddress(6666)); System.out.println("Server start"); //Accept client connection accept asynchronousServerSocketChannel.accept(null,new AcceptCompletionHandler(asynchronousServerSocketChannel)); //The BIO accept operation returns the Socket instance //The AIO accept operation returns AsynchronousSocketChannel //accept is an asynchronous operation, which prevents the current program from directly executing and ending //Method 1: while(ture) +sleep while (true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } catch (IOException e) { e.printStackTrace(); } } }
Callback to accept connection accept (AcceptCompletionHandler.java):
/** * Receive callback for connection accept * @Author : quwenjing * @Date : 2021/11/18 19:07 **/ public class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel,Object > { //Return parameter, pass in parameter private AsynchronousServerSocketChannel channel; public AcceptCompletionHandler(AsynchronousServerSocketChannel channel){ this.channel = channel; } @Override public void completed(AsynchronousSocketChannel result, Object attachment) { System.out.println("New customer connections"); //Complete the accept connection operation //buffer is required for reading and writing operations //Create a new buffer ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //Read the data of the client. The read operation is asynchronous and needs to implement the CompletionHandler object /* void read(ByteBuffer dst,A attachment,CompletionHandler<Integer,? super A> handler); Interpretation of asynchronous mode of read operation dst: Data read destination attachment: information passed to the read callback CompletionHandler: When the data reading is completed, the CompletionHandler object */ result.read(byteBuffer,byteBuffer,new ReadCompletionHandler(result)); //Accept the connection of other clients again and call the accept method channel.accept(null,new AcceptCompletionHandler(channel)); } @Override public void failed(Throwable exc, Object attachment) { } }
Callback for read operation (ReadCompletionHandler.java):
/** * Callback for read operation * @Author : quwenjing * @Date : 2021/11/18 19:21 **/ public class ReadCompletionHandler implements CompletionHandler<Integer,ByteBuffer> { //The result returned by the read operation is the number of reads, which should be Integer //The channel through which the user receives or sends operations private AsynchronousSocketChannel asynchronousSocketChannel; public ReadCompletionHandler(AsynchronousSocketChannel channel){ this.asynchronousSocketChannel = channel; } @Override public void completed(Integer result, ByteBuffer attachment) { //After reading data //The data has been completed and written to the result variable of ByteBuffer type attachment.flip(); byte[] bytes = new byte[attachment.remaining()]; attachment.get(bytes); String string = null; try { string = new String(bytes,"utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } System.out.println("Data received by the server:"+string); attachment.clear(); //Repeatedly receive the message and call the asynchronous read operation again this.asynchronousSocketChannel.read(attachment,attachment,new ReadCompletionHandler(this.asynchronousSocketChannel)); } @Override public void failed(Throwable exc, ByteBuffer attachment) { } }
Client (Client.java):
public class Client { public static void main(String[] args) { //Create asynchronous channel try { AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open(); //Connection server asynchronous mode asynchronousSocketChannel.connect(new InetSocketAddress("127.0.0.1",6666),asynchronousSocketChannel,new ConnectionCompletionHandler()); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //Write operation Scanner scanner = new Scanner(System.in); while (scanner.hasNext()){ String msg = scanner.nextLine(); if (msg!=null && !"".equals(msg.trim())){ byteBuffer.put(msg.getBytes()); byteBuffer.flip(); asynchronousSocketChannel.write(byteBuffer); byteBuffer.clear(); } } } catch (IOException e) { e.printStackTrace(); } } }
Connection server (ConnectionCompletionHandler.java):
public class ConnectionCompletionHandler implements CompletionHandler<Void, AsynchronousSocketChannel> { @Override public void completed(Void result, AsynchronousSocketChannel attachment) { //Successfully connected to the server System.out.println("Successfully connected to the server"); } @Override public void failed(Throwable exc, AsynchronousSocketChannel attachment) { } }