First, we need to clarify a few concepts: synchronous and asynchronous, blocking and non-blocking.
Synchronous and asynchronous
1. The synchronous
When an I/O operation is triggered by a process, handle it in person. Like you have to go to the bank to get the money in person.
2. The asynchronous
When a process triggers an I/O operation, it does not need to handle the operation itself. Instead, the process delegates the operation to the OS. When the process delegates the address and size of the data, it performs other tasks. For example, if you give me your bank card and let me help you to withdraw money from the bank, you need to tell me the password of your bank card and the amount of money to withdraw, and I will give you the money after I finish withdrawing.
3. Summary
Oneself do is synchronous, others do is asynchronous.
Blocking and non-blocking
1.
When a process triggers an I/O operation, if it cannot read or write at this time, the process waits until the read/write operation is complete. For example, if you go to the ATM and there are people waiting in line, you have to wait until you are finished.
2. A non-blocking
When a process triggers an I/O operation, if it cannot read or write at this time, it performs other operations first and then continues to read or write after receiving a notification. For example, you go to the bank counter to take money, more people, that first get a number, waiting for the number to go to the corresponding window for business; What’s slightly inappropriate here is that we have to listen for a call while we wait.
3. Summary
I have to wait and I can’t do anything else which is blocking. I don’t have to wait and I can do something else which is asynchronous.
BIO
Synchronous blocking; A request comes in, the application opens a thread, and when the IO is ready, the IO operation is done by itself. In the BIO server, an independent Acceptor thread is responsible for listening. Call accept() in the while(true) loop and wait for the request from the client; Once the request is received, the socket can be set up for read and write operations, and no further requests can be received until the read and write operations are complete.
In order for the BIO to handle multiple requests at the same time, you need to use multithreading; When the server receives the request, it creates a thread for the client to process, and then destroys the thread after the processing is completed.
However, because a request to start a thread, so the overhead is relatively large, starting and destroying thread overhead is very high, and each thread consumes memory, so we can introduce thread pool, can reduce the overhead of thread creation and destruction to a certain extent; This is also called pseudo-asynchronous IO.
The thread pool maintains N threads and a message queue; When a request comes in, the server passes the Socket as a parameter to a thread task for processing. By controlling the maximum number of threads in the thread pool and the size of the message queue, even if the traffic volume is higher than the capacity of the server, the server will not run out of resources and cause downtime.
This model is efficient when the number of requests is low, and there is no need to consider limiting the number of threads in the thread pool.
NIO
Synchronous non-blocking; Do not wait for IO ready, ready will be notified, but I/O operation still have to do; NIO is a multiplexing mechanism that uses single-thread polling events, channels, to decide what to do, avoiding performance problems (blocking in the Select phase) caused by frequent thread switching when the number of connections is high.
At this point, many of you may be confused… What is multiplexing? What is Channel? What exactly is the Select phase? Let me explain it in vernacular. NIO is buffer-oriented and can read data into a buffer for later processing. NIO has several core concepts:
1. The Channel and Buffer
A Channel can be thought of as a two-way stream, or a Channel, and a Buffer is a cache, or you can think of it as a memory space where data can be streamed from a Channel into a Buffer, or from a Buffer into a Channel. There are many implementations of channels, such as a FileChannel that reads and writes data from a file, a SocketChannel that reads and writes data from a network over TCP, and so on. Buffers also have multiple types, such as ByteBuffer, CharBuffer, IntBuffer, and so on. Just by looking at their names, you can see that they represent different data types.
2. Selector
We can think of a Selector as an administrator, managing multiple channels, and knowing which Channel is ready to read or write. Such a thread only needs to operate the administrator, equivalent to a thread can manage multiple channels; Once a ready Channel is listened on, it can be processed accordingly. But java-native NIO didn’t work until Netty came along.
AIO
Asynchronous non-blocking; Because things are not done by themselves, there is no such thing as blocking (it’s all non-blocking); AIO introduces the concept of asynchronous channel on the basis of NIO. NIO is polling, constantly asking if the data is ready and processing it when it is; AIO is a function that registers IO listening to the operating system. After the operating system completes the IO operation, it actively notifies and triggers the response (do not do it yourself, let the operating system do it).
At present, AIO should not be very widespread.
After reading this article, do you have a preliminary understanding of BIO, NIO, and AIO? If you have any questions, please leave a comment.
Uncle will point code | article “original”