Click “like” to see, form a habit, wechat search [dime technology] pay attention to more original technical articles. This article has been included in GitHub org_Hejianhui /JavaStudy.

preface

Mastering the basic concepts of BIO, NIO, and AIO, as well as faQs, should be an integral part of your interview preparation process, as well as a foundation for learning Netty.

The basic concept

IO model means which channel is used to send and receive data. Java supports three network IO modes: BIO, NIO and AIO. BIO, NIO and AIO in Java are the encapsulation of various IO models of the operating system in Java language. We don’t need relational operating system knowledge to use these apis, nor do we need to write different code for different operating systems.

Before getting into BIO, NIO, and AIO, let’s review a few concepts: synchronous versus asynchronous, blocking versus non-blocking, and I/O models.

Synchronous and asynchronous

  • Synchronization: Synchronization is when a call is made and does not return until the caller has processed the request.
  • Asynchrony: Asynchrony means that after sending a call, the called immediately responds to indicate that the request has been received, but the called does not return the result. In this case, other requests can be processed. The called usually relies on events, callbacks and other mechanisms to notify the caller of the return result.

The biggest difference between synchronous and asynchronous is that in asynchronous case, the caller does not need to wait for the result to be processed. The caller will notify the caller to return the result through some mechanism such as callback.

Blocking and non-blocking

  • Block: A block is when a request is made and the caller waits for the result of the request to return, meaning that the current thread is suspended and cannot continue until the condition is ready.
  • Non-blocking: Non-blocking is making a request so the caller doesn’t have to wait for the result to come back and can do something else first.

Synchronous asynchrony vs. blocking non-blocking (segment)

The Story of Lao Zhang boiling Water (Story source network)

Old Zhang love tea, nonsense do not say, boiled water.

Characters: Lao Zhang, two kettles (ordinary kettles, referred to as kettles; A ringing kettle for short).

  1. Lao Zhang put the kettle on the fire and waited for it to boil. (Synchronous blocking)

Lao Zhang felt a bit silly

  1. Zhang puts the kettle on the fire, goes to the living room to watch TV, and from time to time goes to the kitchen to check whether the water is boiling. (Synchronous non-blocking)

Still feeling a bit silly, Zhang went upscale and bought a kettle that whistled. When the water boils, it makes a loud noise.

  1. Lao Zhang put the kettle on the fire and waited for it to boil. (Asynchronous blocking)

Lao Zhang didn’t see much point in waiting so foolishly

  1. Lao Zhang put the kettle on the fire and went to the living room to watch TV. He stopped looking at the kettle before it rang and went to get it after it rang. (Asynchronous non-blocking)

Lao Zhang feels clever now.

The so-called synchronous asynchronous, only for the kettle

  • Ordinary kettle: synchronous; Ring the kettle: asynchronous.
  • Although they can work, but the ringing kettle can be completed by themselves, the reminder of Lao Zhang’s water is boiling, which is the ordinary kettle can not reach.
  • Synchronization only allows the caller to poll itself (in case 2), making old Zhang inefficient.

The so-called blocking non – blocking, only for Lao Zhang

  • Standing Lao Zhang: blocking; Watching TV: non-blocking.
  • In case 1 and case 3, Lao Zhang was blocked, and his daughter-in-law shouted that he did not know. Although the ringing of the kettle in case 3 is asynchronous, it does not have much significance for Lao Zhang who is standing up. So asynchrony is usually used in conjunction with non-blocking to make asynchrony work.

Common I/O model comparison

All system I/O has two phases: wait-ready and operation.

Read functions, for example, are divided into wait system readable and real read functions. Similarly, write functions can be divided into waiting for the network card to write and real write.

It should be noted that wait-ready blocking does not use the CPU and is “idle waiting”; But the real read operation blocking is using CPU, really “work”, and this process is very fast, belongs to memory copy, bandwidth is usually above 1GB/s level, can be understood as basically time-consuming.

Comparison of the following common I/O models:

Take socket.read() as an example:

  • In traditional BIO, socket.read(), if there is no data in the TCP RecvBuffer, the function blocks until it receives it and returns the read data.
  • For NIO, if the TCP RecvBuffer has data, it reads the data from the network card into memory and returns it to the user. Otherwise, it returns 0 directly and never blocks.
  • AIO(Async I/O) goes a step further: not only is the wait ready non-blocking, but the process of moving data from the card to memory is also asynchronous.

In other words, in BIO the user cares most about “I’m going to read”, in NIO the user cares most about “I can read”, and in AIO the user cares more about “finished reading”.

An important feature of NIO is that the socket’s main read, write, register, and receive functions are non-blocking in the wait-ready phase, while real I/O operations are synchronous blocking (CPU intensive but very high performance).

BIO (Blocking I/O)

Synchronous blocking I/O mode, in which data reads and writes must be blocked in a thread waiting for it to complete (one client connection per processing thread).

Traditional BIO

BIO communication (one request, one reply) model diagram is as follows (figure source network) :usingBIO communication modelThe service team is usually composed of a separateAcceptorThreads are responsible for listening for client connections. We generally pass through thewhile(true)In the loop, the server will callaccept()Waiting for the client connection method to monitor the request, the request once received a connection request, and can establish communication socket on the communication socket to read and write operations, and can’t receive other client connection request at this time, can only wait for the current connection client operation completes, but can be multithreaded to support multiple client connections, As shown above.

Multithreading is necessary if the BIO communication model is to be able to handle requests from multiple clients at the same time (if only because the three main functions involved in socket.accept(), socket.read(), and socket.write() are blocked synchronously). When a connection is processing I/O, the system is blocked, and a single-threaded connection is bound to hang somewhere. Turn on multithreading, and you can force the CPU to do more. That is, it creates a new thread for each client for link processing after receiving the client connection request. After the processing is completed, it is returned to the client through the output stream, and the thread is destroyed. This is the typical one – request – one – reply communication model.

This is the essence of all multithreading:

  • Using the multi-core
  • When the SYSTEM is blocked by I/O but the CPU is idle, you can use multiple threads to consume CPU resources.

We can imagine the following unnecessary thread overhead if the connection does nothing, but this can be mitigated by thread pooling, which also makes thread creation and collection relatively cheap. For example, FixedTreadPool can be used to effectively control the maximum number of threads and ensure limited resource control in the system, implementing a pseudo-asynchronous I/O model with N (number of client requests) : M (number of threads handling client requests) (N can be much greater than M).

Let’s imagine what happens to this model as the number of concurrent client visits increases. As the number of concurrent visits increases, the number of threads expands rapidly. As a result, the stack of threads overflows and new threads fail to be created. As a result, processes break down or die and cannot provide external services.

Threads are a valuable resource in a Java virtual machine.

  1. The cost of creating and destroying a thread is very high, especially in Linux operating system, a thread is essentially a process, creating and destroying a thread are heavyweight system functions;
  2. Threads themselves occupy a large amount of memory, such as The Java thread stack, generally at least 512K to 1M space, if the number of threads in the system is more than a thousand, I am afraid that the entire JVM memory will be eaten up half.
  3. Thread switching costs are also high. When a thread switch occurs in the operating system, the context of the thread needs to be preserved and then the system call is executed. If the number of threads is too high, the execution time of thread switching may even be longer than the execution time of thread. At this time, the system load is usually too high, and the CPU SY usage is especially high (over 20%), resulting in the system almost falling into the state of unavailability.
  4. Jagged system load. Because the system load is based on the number of active threads and CPU cores, once the number of threads is high but the external network environment is not very stable, it is easy to cause a large number of requests to return results at the same time, activate a large number of blocked threads, so that the system load pressure is too large.

Linux system CPU sy > sy high value is the kernel of consumption, if the value of the sy is too high, don’t go to consider is the kernel problem, check first whether out of memory, disk is full, you the problem of IO, is first consider their process problems, for example if IO problems, whether the problems caused by the network. Check whether the SYSTEM I/O or network reaches the bottleneck.

Pseudo asynchronous I/O

In order to solve the synchronous blocking I/O face a link need a thread to handle the problem, then some thread model is optimized for it: the back-end through a thread pool to deal with multiple client requests access to form the client number M: thread pool threads N largest proportion relations, which M can be far greater than N. Through the thread pool, thread resources can be flexibly allocated and the maximum number of threads can be set to prevent thread exhaustion caused by massive concurrent access.

Pseudo asynchronous IO model diagram (figure source network)Using thread pools and task queues, you can implement a framework for I/O communication called pseudo-asynchronous, which is modeled as shown in the figure above. When a new client is connected, the client Socket is encapsulated into a Task (which implements the java.lang.Runnable interface) and sent to the backend thread pool for processing. The JDK thread pool maintains a message queue and N active threads to process the tasks in the message queue. Because the thread pool can set the size of the message queue and the maximum number of threads, its resource usage is manageable, and no matter how many clients access it concurrently, it will not cause resource exhaustion or downtime.

The pseudo-asynchronous I/O communication framework uses a thread pool implementation, thus avoiding the thread resource depletion problem caused by creating a separate thread for each request. However, because its underlying BIO model is still synchronous blocking, it cannot solve the problem fundamentally.

disadvantages

  1. IOIn the codereadThe operation is a blocking operation. If the connection does not perform data read and write operations, the thread will be blocked, wasting resources.
  2. If there are too many threads, the server will be overloaded and stressed.

Application scenarios

BIO mode is suitable for a small and fixed number of connections. This mode requires high server resources, but the program is simple to understand.  

BIO code sample

The service side

package com.niuh.bio;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9000);
        while (true) {
            System.out.println("Waiting for connection...");
            // block method
            final Socket socket = serverSocket.accept();
            System.out.println("A client is connected...");

            // Multithreading
            new Thread(new Runnable() {
                @Override
                public void run(a) {
                    try {
                        handler(socket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

            // Single thread processing
            //handler(socket);}}private static void handler(Socket socket) throws IOException {
        System.out.println("thread id = " + Thread.currentThread().getId());
        byte[] bytes = new byte[1024];

        System.out.println("Ready to read...");
        // Receive data from client, block method, block when there is no data to read
        int read = socket.getInputStream().read(bytes);
        System.out.println("Read complete...");
        if(read ! = -1) {
            System.out.println("Received data from client:" + new String(bytes, 0, read));
            System.out.println("thread id = " + Thread.currentThread().getId());

        }
        socket.getOutputStream().write("HelloClient".getBytes()); socket.getOutputStream().flush(); }}Copy the code

The client

package com.niuh.bio;

import java.io.IOException;
import java.net.Socket;

public class SocketClient {

    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1".9000);
        // Send data to the server
        socket.getOutputStream().write("HelloServer".getBytes());
        socket.getOutputStream().flush();
        System.out.println("Sending data to server completed");
        byte[] bytes = new byte[1024];
        // Receives data from the server
        socket.getInputStream().read(bytes);
        System.out.println("Data received from server:" + newString(bytes)); socket.close(); }}Copy the code

NIO (Non Blocking IO)

Synchronization is non-blocking, and the server implementation mode is that one thread can process multiple requests (connections). All connection requests sent by the client are registered with the selector of the multiplexer, which polls the connection for IO requests and processes them.

It supports buffer-oriented, channel-based approaches to I/O operations. NIO provides two different Socket channel implementations, SocketChannel and ServerSocketChannel, that correspond to Socket and ServerSocket in the traditional BIO model. Both channels support both blocking and non-blocking modes.

  • Blocking mode, like traditional support, is relatively simple, but has poor performance and reliability.
  • Non-blocking mode is the opposite.

For low-load, low-concurrency applications, synchronous blocking I/O can be used for faster development and better maintenance; For high-load, high-concurrency (network) applications, NIO’s non-blocking mode should be used for development.

NIO core components

NIO has three core components:

  • Channel
  • Buffer
  • Selector

The entire NIO architecture contains far more classes than these three, which can only be described as the “core API” of the NIO architecture.

  1. A channel is similar to a stream. Each channel corresponds to a buffer buffer, and the underlying buffer is an array.
  2. A channel registers with a selector, which sends it to an idle thread based on the channel’s read or write events;
  3. A selector can correspond to one or more threads
  4. NIO’s buffers and channels can be both read and written

The characteristics of the NIO

Let’s conclude with a question: What’s the difference between NIO and IO?

NIO streams are non-blocking IO, while IO streams are blocking IO. It can then be analyzed in terms of some of the improvements that NIO’s three core components/features bring to NIO.

IO streams are blocked, NIO streams are not blocked

Java NIO allows us to do non-blocking IO operations. For example, a single thread can read data from a channel to buffer and continue doing other things at the same time. When data is read into buffer, the thread can continue processing data. The same is true for writing data. In addition, non-blocking writes are also routine, where a thread requests to write some data to a channel, but does not have to wait for it to write completely, and the thread can do other things in the meantime.

The various streams of Java IO are blocked, which means that when a thread calls read() or write(), the thread is blocked until some data is read or written completely. The thread can’t do anything else in the meantime.

IO Stream oriented, NIO Buffer oriented

Buffer

A Buffer is an object that contains some data to be written or read. The addition of Buffer objects to the NIO class library illustrates an important difference in I/O between the new library and the original library:

  • In stream-oriented I/O, data can be written directly or read directly into a Stream object. Although there are extension classes opened by Buffer in Stream, they are just wrapper classes for the Stream and read from the Stream to the Buffer.
  • NIO reads directly into Buffer. In the NIO library, all data is handled with buffers. When reading data, it reads directly into the buffer; When data is written, it is written to the cache. Any time you access data in NIO, you are operating through the buffer.

The most commonly used buffer is the ByteBuffer, which provides a set of functions for manipulating byte arrays. There are other buffers besides ByteBuffers, and in fact, there should be a buffer for every Java primitive (except Boolean) type.

NIO reads and writes through channels

Channel

A channel is bidirectional and can be read or written, while a stream reads and writes in one direction. Channels can only interact with buffers, whether they are read or written. Because of buffers, channels can be read and written asynchronously.

NIO has selectors, while IO does not

Selectors

Selectors are used to process multiple channels using a single thread. Therefore, it requires fewer threads to process these channels. Switching between threads can be expensive for an operating system. Therefore, in order to provide system efficiency selectors are useful.

NIO reads and writes data

In general, all IO in NIO starts with a Channel.

  • Read data from the channel: create a buffer and ask the channel to read data;
  • Write data from channel: Create a buffer, populate the data, and ask the channel to write data.

The data reads and writes are as follows:

Application scenarios

NIO is suitable for architectures with a large number of connections and relatively short connections (light operation), such as chat server, bullet screen system, communication between servers, and complicated programming.

NIO code sample

The service side

package com.niuh.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NIOServer {

    //public static ExecutorService pool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws IOException {
        // Create a service Socket channel that listens on the local port. And set it to non-blocking mode
        ServerSocketChannel ssc = ServerSocketChannel.open();
        // It must be configured to be non-blocking to register with a selector, otherwise an error will be reported. The selector mode itself is non-blocking
        ssc.configureBlocking(false);
        ssc.socket().bind(new InetSocketAddress(9000));
        // Create a selector
        Selector selector = Selector.open();
        // Register a ServerSocketChannel with a Selector that is interested in the client accept connection
        ssc.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            System.out.println("Waiting for something to happen...");
            // Polling listens for key in a channel. Select is blocked, and accept() is blocked
            int select = selector.select();

            System.out.println("Something has happened...");
            // There is a client request, which is monitored by polling
            Iterator<SelectionKey> it = selector.selectedKeys().iterator();
            while (it.hasNext()) {
                SelectionKey key = it.next();
                // Delete the key that has been processed this time to prevent repeat processing next timeit.remove(); handle(key); }}}private static void handle(SelectionKey key) throws IOException {
        if (key.isAcceptable()) {
            System.out.println("A client connection event occurred.");
            ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
            NIO is not blocking: here the accept method is blocking, but here the connection event occurred, so the method will execute immediately without blocking
            // The connection request is processed without waiting for the client to send data
            SocketChannel sc = ssc.accept();
            sc.configureBlocking(false);
            // Interested in reading events when listening for a Channel through Selector
            sc.register(key.selector(), SelectionKey.OP_READ);
        } else if (key.isReadable()) {
            System.out.println("Client data readable event occurred.");
            SocketChannel sc = (SocketChannel) key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            //NIO is non-blocking: first, the read method does not block, and second, the event response model is that when the read method is called, the client must send data
            int len = sc.read(buffer);
            if(len ! = -1) {
                System.out.println("Read data sent by client:" + new String(buffer.array(), 0, len));
            }
            ByteBuffer bufferToWrite = ByteBuffer.wrap("HelloClient".getBytes());
            sc.write(bufferToWrite);
            key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
        } else if (key.isWritable()) {
            SocketChannel sc = (SocketChannel) key.channel();
            System.out.println("Write");
            // NIO event triggering is horizontal
            // Cancel the write event when there is no data to write out.
            // Register write events when data is written out
            key.interestOps(SelectionKey.OP_READ);
            //sc.close();}}}Copy the code

NIO server program detailed analysis:

  1. Create a ServerSocketChannel and Selector, and register the ServerSocketChannel with the Selector.
  2. The Selector listens for a channel event through the Select () method. When the client connects, the Selector listens for the connection event and gets the selectionKey bound to the ServerSocketChannel registration.
  3. SelectionKey gets the bound ServerSocketChannel through the channel() method;
  4. ServerSocketChannel The accept() method is used to get the SocketChannel.
  5. Register SocketChannel with Selector, care about read event;
  6. After registration, a SelectionKey is returned, which is associated with the SocketChannel.
  7. The Selector continues to listen for events through the Select () method. When the client sends data to the server, the Selector listens for the read event and gets the SelectionKey bound to the SocketChannel registry.
  8. The SelectionKey gets the bound socketChannel through the channel() method;
  9. Read data from socketChannel.
  10. Write server data back to the client using socketChannel.

The client

package com.niuh.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NioClient {
    // Channel manager
    private Selector selector;

    /** * Start client test **@throws IOException
     */
    public static void main(String[] args) throws IOException {
        NioClient client = new NioClient();
        client.initClient("127.0.0.1".9000);
        client.connect();
    }

    /** * get a Socket channel and do some initialization for the channel **@paramIP IP address of the connected server *@paramPort Port number of the connected server *@throws IOException
     */
    public void initClient(String ip, int port) throws IOException {
        // Get a Socket channel
        SocketChannel channel = SocketChannel.open();
        // Set the channel to non-blocking
        channel.configureBlocking(false);
        // Get a channel manager
        this.selector = Selector.open();

        // The client connects to the server, but the connection is not implemented in the listen () method
        // Use channel.finishConnect() to complete the connection
        channel.connect(new InetSocketAddress(ip, port));
        // Bind the channel manager to the channel and register the selectionkey.op_connect event for the channel.
        channel.register(selector, SelectionKey.OP_CONNECT);
    }

    /** * polls the selector to see if there is an event that needs to be handled, and if there is an event that needs to be handled@throws IOException
     */
    public void connect(a) throws IOException {
        // Polls to access selector
        while (true) {
            selector.select();
            // Get an iterator for the selected item in selector
            Iterator<SelectionKey> it = this.selector.selectedKeys().iterator();
            while (it.hasNext()) {
                SelectionKey key = (SelectionKey) it.next();
                // Delete the selected key to prevent duplicate processing
                it.remove();
                // A connection event occurred
                if (key.isConnectable()) {
                    SocketChannel channel = (SocketChannel) key.channel();
                    // If you are connecting, complete the connection
                    if (channel.isConnectionPending()) {
                        channel.finishConnect();
                    }
                    // Set to non-blocking
                    channel.configureBlocking(false);
                    // This is where you can send messages to the server
                    ByteBuffer buffer = ByteBuffer.wrap("HelloServer".getBytes());
                    channel.write(buffer);
                    // Set read permission for the channel to receive messages from the server after the connection is successful.
                    channel.register(this.selector, SelectionKey.OP_READ);                                            // Get readable events
                } else if(key.isReadable()) { read(key); }}}}/** * Handle the event that reads the message sent by the server **@param key
     * @throws IOException
     */
    public void read(SelectionKey key) throws IOException {
        // The same as the read method on the server
        // The server can read the message: get the Socket channel where the event occurred
        SocketChannel channel = (SocketChannel) key.channel();
        // Create a buffer for reading
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int len = channel.read(buffer);
        if(len ! = -1) {
            System.out.println("Client receives message:" + new String(buffer.array(), 0, len)); }}}Copy the code

conclusion

The SELECTOR in the NIO model is like a big header that listens for various I/O events and then passes them on to a back-end thread to handle.

NIO is non-blocking relative to BIO: the BIO back-end thread blocks waiting for the client to write data (such as the read method), and blocks if the client does not write data.

The selector is responsible for polling all registered clients. When it finds that an event has occurred, the selector is transferred to the backend thread for processing. The backend thread does not need to do any blocking waiting, but directly processes the data of the client event. Or return the thread pool for continued use by other client events. Also, the channel reads and writes are non-blocking.

Redis is the typical NIO thread model. The selector collects all the events and passes them to the back-end thread, which executes all the event commands continuously and writes the results back to the client.

AIO (Asynchronous I/O)

Asynchronous non-blocking, the operating system after the completion of the callback notified the server program to start the thread to process, generally applicable to a large number of connections and a long connection time applications.

AIO is NIO 2. NIO 2, an improved version of NIO introduced in Java 7, is an asynchronous, non-blocking IO model. Asynchronous IO is implemented based on events and callbacks, meaning that an action is applied and returned, not blocked, and when the background processing is complete, the operating system notifies the appropriate thread to proceed with the subsequent action.

AIO is short for asynchronous IO. Although NIO provides a non-blocking method for network operations, NIO’s I/O behavior is synchronous. For NIO, our business thread is notified when the IO operation is ready, and then the thread performs the IO operation itself, which is synchronous. (All IO types are synchronous except AIO)

Application scenarios

The AIO mode applies to architectures with a large number of connections and long connections (heavy operations).

AIO code sample

The service side

package com.niuh.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;

public class AIOServer {
    public static void main(String[] args) throws Exception {
        final AsynchronousServerSocketChannel serverChannel =
                AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(9000));

        serverChannel.accept(null.new CompletionHandler<AsynchronousSocketChannel, Object>() {
            @Override
            public void completed(final AsynchronousSocketChannel socketChannel, Object attachment) {
                try {
                    // If you do not write this line of code, the client connection will not connect to the server
                    serverChannel.accept(attachment, this);
                    System.out.println(socketChannel.getRemoteAddress());
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    socketChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
                        @Override
                        public void completed(Integer result, ByteBuffer buffer) {
                            buffer.flip();
                            System.out.println(new String(buffer.array(), 0, result));
                            socketChannel.write(ByteBuffer.wrap("HelloClient".getBytes()));
                        }

                        @Override
                        public void failed(Throwable exc, ByteBuffer buffer) { exc.printStackTrace(); }}); }catch(IOException e) { e.printStackTrace(); }}@Override
            public void failed(Throwable exc, Object attachment) { exc.printStackTrace(); }}); Thread.sleep(Integer.MAX_VALUE); }}Copy the code

The client

package com.niuh.aio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;

public class AIOClient {

    public static void main(String... args) throws Exception {
        AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();
        socketChannel.connect(new InetSocketAddress("127.0.0.1".9000)).get();
        socketChannel.write(ByteBuffer.wrap("HelloServer".getBytes()));
        ByteBuffer buffer = ByteBuffer.allocate(512);
        Integer len = socketChannel.read(buffer).get();
        if(len ! = -1) {
            System.out.println("Client receives message:" + new String(buffer.array(), 0, len)); }}}Copy the code

BIO, NIO, AIO

BIO NIO AIO
IO model A synchronized block Synchronous non-blocking (multiplexing) Asynchronous nonblocking
Programming difficulty simple complex complex
reliability poor good good
throughput low high high

PS: The above code is submitted to Github: github.com/Niuh-Study/…

GitHub Org_Hejianhui /JavaStudy