Java NIO: Analysis of the I/O model and nio Analysis

Source: Internet
Author: User
Tags high cpu usage

Java NIO: Analysis of the I/O model and nio Analysis

Notes for learning Java !!!

If you have any questions or want to obtain learning resources during the learning process, join the Java learning exchange group: 618528494 let's learn Java together!

Many friends may feel a little hard to learn NIO, but they do not feel so clear about many concepts. Before entering Java NIO programming, we will discuss some basic knowledge today: I/O models. Next, we will start with the concepts of synchronization and Asynchronization. Next we will discuss the differences between blocking and non-blocking, and then introduce the differences between blocking IO and non-blocking IO, the differences between synchronous I/O and asynchronous I/O are introduced. Next, five I/O models are introduced. Finally, two design modes (Reactor and Proactor) related to high-performance I/O design are introduced ).

The following is the directory outline of this article:

1. What is synchronization? What is asynchronous?

2. What is blocking? What is non-blocking?

3. What is blocking I/O? What is non-blocking IO?

4. What is synchronous I/O? What is asynchronous IO?

5. Five IO Models

Vi. Two high-performance IO Design Modes

If there are any mistakes, please forgive me and welcome criticism and correction.

1. What is synchronization? What is asynchronous?

It has been a long time since the concepts of synchronization and Asynchronization come out. There are also many online syncing and Asynchronization statements. My personal understanding is as follows:

Synchronization means that if multiple tasks or events occur, these tasks or events must be performed one by one. The execution of one event or task will temporarily wait for the entire process, these events cannot be executed concurrently;

Asynchronous means that if multiple tasks or events occur, these events can be executed concurrently. The execution of an event or task will not temporarily wait for the entire process.

This is synchronous and asynchronous. For example, assume that A task includes two subtasks A and B. For synchronization, when A is in the execution process, B only waits until A is completed, B can be executed. for asynchronous mode, A and B can be executed concurrently, and B does not have to wait until A completes execution, so that the execution of A does not lead to the temporary waiting of the entire task.

If you do not understand it, you can read the following two sections of code:

1234567891011121314 void fun1() {         }     void fun2() {         }     void function(){      fun1();      fun2()      .....      .....  }

This code is a typical synchronization. In method functions, fun1 will cause subsequent fun2 to fail to be executed during execution, and fun2 must wait until fun1 is executed.

Next, let's look at the following code:

123456789101112131415161718192021222324 void fun1() {     } void fun2() {     } void function(){    new Thread(){        public void run() {            fun1();        }    }.start();         new Thread(){        public void run() {            fun2();        }    }.start();     .....    .....}

This code is a typical asynchronous process. The execution of fun1 will not affect the execution of fun2, and the execution of fun1 and fun2 will not cause the subsequent execution to be temporarily waiting.

In fact, synchronization and Asynchronization are a very broad concept. Their focus is on whether the occurrence or execution of an event will lead to a temporary wait for the entire process when multiple tasks and events occur. I think it is possible to associate synchronization and Asynchronization with the synchronized keyword in Java for an analogy. When multiple threads access a variable at the same time, it is an event for each thread to access the variable. For synchronization, these threads must access the variable one by one, when a thread accesses the variable, other threads must wait. For Asynchronization, multiple threads do not have to access the variable one by one and can access the variable at the same time.

Therefore, I personally think that synchronization and Asynchronization can be manifested in many aspects, but remember that the key is that when multiple tasks and events occur, whether the occurrence or execution of an event will temporarily wait for the entire process. Generally, asynchronous mode can be implemented through multiple threads, but do not draw equal signs between multithreading and Asynchronization. Asynchronization is only a macro mode. multithreading is just a means to achieve Asynchronization, asynchronous mode can also be implemented through multi-process.

2. What is blocking? What is non-blocking?

The difference between synchronous and asynchronous is introduced earlier. This section describes the difference between blocking and non-blocking.

Blocking means that when an event or task is executing, it sends a request operation. However, because the conditions required for this request operation are not met, it will wait there, until the conditions are met;

Non-blocking means that when an event or task is executing, it sends a request operation. If the conditions required for this request operation are not met, A flag message is returned immediately, indicating that the condition is not met and it will not be waiting there.

This is the difference between blocking and non-blocking. That is to say, the key difference between blocking and non-blocking is that when a request is sent for an operation, if the condition is not met, it will always wait or return a flag information.

A simple example:

If I want to read the content of a file, if there is no readable content in the file at this time, it will remain there for synchronization until the file contains readable content; for non-blocking, A flag is directly returned to inform the file that no content is readable.

On the Internet, some friends draw equal signs for synchronization and Asynchronization, respectively, with blocking and non-blocking. In fact, they are completely different concepts of the two groups. Note: understanding the differences between the two concepts is very important for the later I/O models.

Synchronization and Asynchronization focus on whether the execution of a single task will temporarily wait the entire process during the execution of multiple tasks;

Blocking and non-blocking focuses on whether a flag information will be returned if the conditions for the operation are not met when a request is sent.

Understanding blocking and non-blocking can be analogous to thread blocking. When a thread performs a request operation, if the condition is not met, it will be blocked, that is, when the waiting condition is met.

3. What is blocking I/O? What is non-blocking IO?

Before learning about blocking IO and non-blocking IO, Let's first look at the next specific IO operation process.

Generally, I/O operations include hard disk reading and writing, socket reading and writing, and peripheral reading and writing.

When a user thread initiates an IO request operation (This article uses the Read Request operation as an example), the kernel will check whether the data to be read is ready. For IO blocking, if the data is not ready, wait until the data is ready. For non-blocking IO, if the data is not ready, a flag is returned to inform the user thread that the data to be read is not ready. When the data is ready, the data is copied to the user thread to complete a complete IO Read Request operation. That is to say, a complete IO Read Request operation involves two phases:

1) check whether the data is ready;

2) copy data (the kernel copies the data to the user thread ).

The difference between blocking IO and non-blocking IO lies in the first stage. If the data is not ready, you will always wait until you check whether the data is ready, or directly return a flag information.

In Java, the traditional IO is blocking IO, for example, reading data through socket. After the read () method is called, if the data is not ready, the current thread will always block the read method call, it is returned only when there is data. If the IO is not blocked, when the data is not ready, the read () method should return a flag to inform the current thread that the data is not ready, instead of waiting there all the time.

4. What is synchronous I/O? What is asynchronous IO?

Let's take a look at the definition of synchronous IO and asynchronous IO. The definition of synchronous IO and asynchronous IO in Unix network programming is as follows:

  A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes.
  An asynchronous I/O operation does not cause the requesting process to be blocked.

It can be seen from the literal meaning: Synchronous IO means that if a thread requests IO operations, the thread will be blocked before the IO operation is completed;

Asynchronous IO does not block the request thread if a thread requests IO operations.

In fact, synchronous I/O and asynchronous I/O models are for the interaction between the user line and the kernel:

For synchronous I/O: After you send an I/O request, if the data is not ready, you must use the user thread or kernel to continuously check whether the data is ready. When the data is ready, then copy the data from the kernel to the user thread;

Asynchronous IO: only the sending of IO request operations is performed by the user thread. The two phases of IO operations are automatically completed by the kernel, and then a notification is sent to inform the user thread that the IO operation has been completed. That is to say, in asynchronous IO, there will be no blocking on the user thread.

This is the key difference between synchronous IO and asynchronous IO. The key difference between synchronous IO and asynchronous IO is whether the data is completed by the user thread or the kernel in the data copy phase. Therefore, asynchronous IO must be supported by the underlying operating system.

Note that synchronous IO and asynchronous IO are different from blocking IO and non-blocking IO.

Blocking I/O and non-blocking I/O are reflected in the fact that when a user requests an I/O operation, if the data is not ready, the user thread waits until the data is ready, or will still receive a flag information above. That is to say, blocking IO and non-blocking IO are reflected in the first stage of IO operations, and how they are processed when checking whether the data is ready.

5. Five IO Models

In Unix network programming, five I/O models are mentioned: Blocking IO, non-blocking IO, multiplexing IO, signal-driven IO, and asynchronous IO.

The similarities and differences between the five I/O models are described below.

1. Block IO Model

The most traditional I/O model, that is, blocking occurs during data reading and writing.

When the user thread sends an IO request, the kernel will check whether the data is ready. If not, it will wait for the data to be ready, and the user thread will be in a blocking state, and the user thread will hand over the CPU. When the data is ready, the kernel copies the data to the user thread and returns the result to the user thread. The user thread unblocks the data.

A typical blocking IO model is as follows:

1 data = socket.read();

If the data is not ready, it will always block the read method.

2. Non-blocking IO Model

After the user thread initiates a read operation, it does not need to wait, but immediately gets a result. If the result is an error, it will know that the data is not ready, so it can send the read operation again. Once the data in the kernel is ready and again receives a request from the user thread, it immediately copies the data to the user thread and returns it.

In fact, in the non-blocking IO model, the user thread needs to constantly ask whether the kernel data is ready, that is, non-blocking IO will not hand over the CPU, but will continue to occupy the CPU.

The typical non-blocking IO model is generally as follows:

1234567 while(true){    data = socket.read();    if(data!= error){        Process Data        break;    }}

However, there is a very serious problem with non-blocking I/O. In the while LOOP, You need to constantly ask whether the kernel data is ready, which will cause high CPU usage, therefore, the while loop is rarely used to read data.

3. multiplexing IO Model

Multiplexing I/O models are currently widely used. Java NIO is actually multiplexing IO.

In the multiplexing IO model, a thread continuously polls the status of multiple sockets. The actual IO read/write operation is called only when the socket actually has a read/write event. In the multiplexing I/O model, you only need to use one thread to manage multiple sockets. The system does not need to create new processes or threads or maintain these threads or processes, IO resources are used only when a socket read/write event exists, which greatly reduces resource usage.

In Java NIO, it uses selector. select () is used to query whether an event arrives in each channel. If no event exists, the event is blocked. Therefore, this method causes user thread blocking.

Some may say that I can use multithreading + Blocking IO to achieve similar results. However, in multithreading + Blocking IO, each socket corresponds to a thread, this will cause a lot of resource occupation, and especially for persistent connections, the thread resources will not be released. If there are many connections in the future, it will cause performance bottlenecks.

In multiplexing I/O mode, multiple sockets can be managed through one thread. Resources are occupied only when a real read/write event occurs in the socket for actual read/write operations. Therefore, multiplexing IO is more suitable for scenarios with a large number of connections.

In addition, the reason why multiplexing IO is more efficient than the non-blocking IO model is that in non-blocking IO, the user thread is used to continuously ask the socket status, while in Multiplexing IO, polling each socket status is carried out by the kernel, which is much more efficient than the user thread.

However, it should be noted that the multiplexing I/O model checks whether events arrive by polling and responds to events one by one. Therefore, for the multiplexing IO model, once the event response body is large, the subsequent events will be delayed and new event polling will be affected.

4. Signal-driven I/O model

In the signal-driven I/O model, when a user thread initiates an I/O Request operation, it registers a signal function for the corresponding socket, and the user thread continues to execute the function, when the kernel data is ready, a signal is sent to the user thread. After receiving the signal, the user thread calls the IO read/write operation in the signal function to perform the actual IO request operation.

5. asynchronous IO Model

The asynchronous IO model is the ideal I/O model. In the asynchronous I/O model, when a user thread initiates a read operation, it can immediately start to do other things. On the other hand, from the kernel perspective, when it receives an asynchronous read, it will immediately return, indicating that the read request has been initiated successfully, so it will not generate any block to the user thread. Then, the kernel will wait for the data preparation to complete, and then copy the data to the user thread. After all this is done, the kernel will send a signal to the user thread to tell it that the read operation is complete. That is to say, the user thread does not need to perform the entire I/O operation at all. You only need to initiate a request first. When receiving the successful signal returned by the kernel, the I/O operation has been completed, you can use the data directly.

That is to say, in the asynchronous IO model, neither phase of the IO operation will block the user thread. Both stages are automatically completed by the kernel, and then a signal is sent to inform the user that the thread operation has been completed. The user thread does not need to call the IO function again for specific read/write. This is different from the signal-driven model. In the signal-driven model, when the user thread receives the signal, it indicates that the data is ready, and then the user thread needs to call the IO function for actual read/write operations; in the asynchronous I/O model, the received signal indicates that the I/O operation has been completed and no need to call the I/O function in the user thread for actual read/write operations.

Note that Asynchronous IO requires the underlying support of the operating system. In Java 7, Asynchronous IO is provided.

The first four IO models are actually synchronous I/O. Only the last one is real asynchronous I/O, because whether it is a multiplexing IO or a signal-driven model, the first phase of the I/O operation will cause user thread blocking, that is, the data copy process of the kernel will cause user threads to block.

Vi. Two high-performance IO Design Modes

In the traditional network service design model, there are two classic models:

One is multithreading and the other is the thread pool.

In the multi-threaded mode, the server creates a thread to process the read/write events of the client, as shown in:

This mode is easy to process, but the server uses a thread to process the connection of each client, so the resource usage is very large. Therefore, when the number of connections reaches the upper limit, user requests for connections will directly lead to resource bottlenecks, and serious problems may directly lead to server crashes.

Therefore, in order to solve the problem that a thread corresponds to a client mode, a thread pool is used to create a fixed-size thread pool for a client, take an idle thread from the thread pool for processing. After the client completes read/write operations, it will hand over the occupation of the thread. Therefore, this avoids the waste of resources caused by thread creation for each client, so that the thread can be reused.

However, the thread pool also has its drawbacks. if most of the connections are persistent connections, this may cause the threads in the thread pool to be occupied for a period of time. When a user requests a connection, because there is no idle thread available for processing, the client connection will fail, thus affecting the user experience. Therefore, the thread pool is suitable for a large number of transient connection applications.

Therefore, the following two high-performance IO Design modes are available: Reactor and Proactor.

In Reactor mode, events of interest are registered for each client first, and a thread specifically polls whether an event occurs for each client. when an event occurs, each event is processed sequentially. After all events are processed, round robin continues, as shown in:

From this we can see that the multiplexing IO in the above five IO models adopts the Reactor mode. Note: The figure above shows how to process each event in sequence. To speed up event processing, you can process the event through multiple threads or thread pools.

In Proactor mode, when an event is detected, a new asynchronous operation is initiated and then processed by the kernel thread. After the kernel thread completes the IO operation, the Proactor mode is used to send a notification indicating that the operation has been completed.

Notes for learning Java !!!

If you have any questions or want to obtain learning resources during the learning process, join the Java learning exchange group: 618528494 let's learn Java together!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.