BIO, NIO, AIO summary

Java in BIO, NIO and AIO understood as a package of various IO models of Java language of the operating system. Programmers in the use of these API's, do not care about the operating system level knowledge, nor need to write different code for different operating systems. Only you need to use the Java API on it.

In speaking BIO, NIO, before AIO first to review the following concepts: synchronous and asynchronous, blocking and non-blocking.

Synchronous and asynchronous:

  • Synchronization: Synchronization is initiating a call, the complete request before it is untreated caller, calls are not returned.
  • Asynchronous: Asynchronous is to initiate a call, the caller is immediately get a response indicates request has been received, but the caller did not return results, then we can deal with other requests, the caller usually rely on the event, such as a callback mechanism to inform the caller that returns the result.

The biggest difference between synchronous and asynchronous is asynchronous if the caller does not need to wait for the result of the processing , the caller will pass a callback mechanisms to inform the caller that returns the result.

Blocking and non-blocking:

  • Blocking: blocking a request is initiated, the caller has been waiting for a request to return the results, that is, the current thread is suspended, unable to engage in other tasks only when the conditions are ready to continue.
  • Non-blocking: Non-blocking is initiated by a request, the caller has been waiting for the results do not return, you can go do other things.

For life simple example, your mother let you boil water, a child you compare Bena, where the water is just wait ( synchronous blocking ). And then wait for you to grow up a little bit, you know the gap can boil every time doing something else, then only need from time to time to see if the water is not opened ( synchronous non-blocking ). Later, your home on the open water jug will sound, so you just need to know after hearing the sound of open water, during which you can easily do their own thing, you need to pour the ( asynchronous non blocking ).

1. BIO (Blocking I/O)


Synchronous blocking I / O mode, the read data is written to be blocked waiting for its completion within a thread.
1.1 Traditional BIO

BIO communication (a request-response) model diagram below (FIG source network, the original source unknown):
Here Insert Picture Description
using BIO communication model server, usually by an independent thread of Acceptor listening client connections. We generally by while(true)the server will be invoked loop accept()mode waiting to receive the client end of the connection method interception request, a connection request upon receiving the request, the communication can be established sockets for read and write operations on the communication socket, then other clients can not receive connection requests, to wait with the operation of the client currently connected executed, but can support multiple client connections, through multi-threaded as shown in FIG.

If you want BIO communication model capable of simultaneously processing a plurality of client requests, it is necessary to use multiple threads (mainly due to the socket.accept()、socket.read()、socket.write()following three main functions involved are synchronized blocked), that is to say it receives a connection request to the client after each client to create a new thread link processing, processing is completed, the output stream is returned by the response to the client, the thread destroyed. This is typical of a request-response communication model . We can imagine that if this link does nothing, then it will cause unnecessary thread overhead, but by the thread pool mechanism improved thread pool also allows to create threads and recycling costs are relatively low. Use FixedThreadPoolcan effectively control the maximum number of threads, to ensure that the limited control of the system resources, to achieve the N (client request Number): M (number of threads handling client requests) pseudo-asynchronous I / O model (N can be far greater than M), following a "pseudo asynchronous BIO" will be described in detail to.

Let us imagine when we add the amount of concurrent access to the client what the problem with this model occur?

In the Java virtual machine, the thread is a precious resource, thread creation and destruction of the high cost, in addition, thread switching cost is very high. Especially in this operating system Linux, the thread is essentially a process of creating and destroying threads are heavyweight system function. If you increase the amount of concurrent access can cause rapid expansion of the number of threads may cause the thread stack overflow, creating a new thread failure and other problems, eventually leading to process downtime or dead, can not provide services.

1.2 Pseudo Asynchronous IO

In order to solve a problem link synchronous blocking I / O needs faced by a thread processing, and later was its threading model is optimized to handle one hundred eleven backend request access to multiple clients through a thread pool to form a customer the number of ends M: maximum number of threads N is the ratio between the thread pool, where M may be much greater than N. deploy flexible thread through the thread pool resource, the maximum set of threads, to prevent concurrent access leading to massive depletion of the thread.

FIG pseudo asynchronous IO model (FIG source network, the original source unknown):
Here Insert Picture Description
thread pool may be implemented, and the task queue called I / O pseudo-asynchronous communication framework, its model map as shown in FIG. When there is access to a new client, the client will be packaged into a Socket Task (This task is implemented java.lang.Runnable interface) delivered to the rear end of the thread pool is processed, the JDK thread pool maintains a message queue and N active threads, message queue processing tasks. Since the thread pool can set the size and the maximum number of threads message queue, therefore, its footprint is controllable, no matter how many clients concurrent access, will not lead to the depletion of resources and downtime.

Pseudo asynchronous I / O communications framework uses a thread pool implementation, thus avoiding thread resources are created for each request a separate thread caused by exhaustion. But because it is still the underlying BIO synchronous blocking model, it can not solve the problem fundamentally.

Code Example 1.3

The following code illustrates a communication BIO (a request-response) model. We will create multiple threads in turn connected client server and sends the "current time +: hello world", the server creates a thread for each client thread to handle. Flash code examples from the blog, the original address as follows:
https://www.jianshu.com/p/a4e03835921a

Client

/**
 * 
 * @author 闪电侠
 * @date 2018年10月14日
 * @Description:客户端
 */
public class IOClient {

  public static void main(String[] args) {
    // TODO 创建多个线程,模拟多个客户端连接服务端
    new Thread(() -> {
      try {
        Socket socket = new Socket("127.0.0.1", 3333);
        while (true) {
          try {
            socket.getOutputStream().write((new Date() + ": hello world").getBytes());
            Thread.sleep(2000);
          } catch (Exception e) {
          }
        }
      } catch (IOException e) {
      }
    }).start();

  }

}

Server

/**
 * @author 闪电侠
 * @date 2018年10月14日
 * @Description: 服务端
 */
public class IOServer {

  public static void main(String[] args) throws IOException {
    // TODO 服务端处理客户端连接请求
    ServerSocket serverSocket = new ServerSocket(3333);

    // 接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理
    new Thread(() -> {
      while (true) {
        try {
          // 阻塞方法获取新的连接
          Socket socket = serverSocket.accept();

          // 每一个新的连接都创建一个线程,负责读取数据
          new Thread(() -> {
            try {
              int len;
              byte[] data = new byte[1024];
              InputStream inputStream = socket.getInputStream();
              // 按字节流方式读取数据
              while ((len = inputStream.read(data)) != -1) {
                System.out.println(new String(data, 0, len));
              }
            } catch (IOException e) {
            }
          }).start();

        } catch (IOException e) {
        }

      }
    }).start();

  }

}

1.4 summary

In the case of active connections is not particularly high (less than stand-alone 1000), and this model is quite good, allowing each to focus on their connected I / O and simple programming model, they do not give much thought to overload the system, issues such as limiting. Thread pool itself is a natural funnel, some systems can not deal with a buffer or a connection request. However, when connected to the face of thousands or even one million, BIO traditional model is powerless. Therefore, we need a more efficient I / O processing model to cope with higher concurrency.

2. NIO (New I / O)


About 2.1 NIO

NIO is a synchronous non-blocking I / O model , incorporated in the Java 1.4 NIO frame corresponding java.nio package, provided Channel , Selector,Bufferthe abstract.

NIO N can be understood as the Non-blocking, not simply New. It supports buffer-oriented, channel-based I / O operation method. NIO provides traditional BIO models Socketand ServerSocketcorresponding SocketChanneland ServerSocketChanneltwo different socket channel to achieve both channel supports blocking and non-blocking modes. Blocking mode using just tradition, like support, is relatively simple, but the performance and reliability is not good; just the opposite non-blocking mode. For low load, low concurrent applications, can use synchronous blocking I / O rate and to enhance the development of better maintenance; high load, high concurrency (network) applications, use of non-blocking mode to develop NIO.

Characteristics of 2.2 NIO / NIO and IO difference

If it is to answer this question in the interview, I feel sure from the first stream is NIO non-blocking IO and IO IO Speaking flow is blocked. Then, we can bring some improvements to NIO NIO from the three core components / features to analyze. If you put them all on the answer to NIO I think you have a little more in-depth understanding of the interviewer to ask you this question, you can also easily answer will come up.

1) Non-blocking IO (nonblocking the IO)
the IO stream is blocked, NIO flow is not blocked.

Java NIO so that we can carry out non-blocking IO operations. For example, a single thread to read data from the channel to buffer, and can continue to do other things, when reading the data to the buffer, the thread to continue processing data. Write data is the same. In addition, non-blocking write is true. A thread requests to write some data to a channel, but do not need to wait for it to be completely written, this thread can do something else at the same time.

Various Java IO streams are blocked. This means that when a thread calls read()or write()when the thread is blocked until there is some data to be read, or the data is completely written. The thread in the meantime can not do it again any thing

2) Buffer (buffer)

IO stream oriented (Stream oriented), while facing NIO buffer (Buffer oriented).

Buffer is an object that contains data to be written or to be read out. Buffer objects NIO libraries to join in, and reflect a new library is an important difference with the original I / O's. In the stream-oriented I / O, data may be written directly · or read directly Stream object data. Although Stream is also the beginning of the Buffer extension classes, but only flow wrapper class, or read from the stream buffer, and NIO Buffer is read directly in the operation.

In NIO She, all data are treated with buffer. When reading data, which is read directly buffer; when data is written, is written into the buffer. Any time access to data in the NIO, are operated by the buffer.

The most common buffer is ByteBuffer, ByteBuffer provides a set of functions for operating a byte array. In addition ByteBuffer, there are other buffers, in fact, every Java primitive types (except Boolean type) corresponds to have a buffer.

3) Channel (channel)

Channel read or written by NIO (channel).

The channel is bidirectional, readable and writable, and read the flow is unidirectional. Whether reading and writing, and only channel Buffer interaction. Because Buffer, read channel may asynchronously.

4) Selectors (selector)

There NIO selector, but no IO.

Selector for processing multiple channels using a single thread. Thus, it requires less thread to handle these channels. Switching between threads to the operating system is expensive. Therefore, to improve the efficiency of the system is useful choice.

Here Insert Picture Description
2.3 NIO read data and write data mode

Generally, in all IO NIO it is from Channel (channel) began.

  • Data read from the channel: create a buffer, and then read the data request channel.
  • Writing data from the channel: create a buffer, stuffing data, write data and request channel.

Data read and write operations illustrated:
Here Insert Picture Description
2.4 introduces the NIO core components

NIO contains several core components of the following:

  • Channel (Channel)
  • Buffer (buffer)
  • Selector (selector)

NIO system contains the entire class far more than these three, only three said it was NIO system "core API". We have above these three concepts are basic exposition here is not to do more to explain.

Code Example 2.5

Flash code examples from the blog, the original address as follows:
https://www.jianshu.com/p/a4e03835921a

IOClient.java client code remains unchanged, we use NIO to transform the server. The following code more and more complex logic, it looks like.

/**
 * 
 * @author 闪电侠
 * @date 2019年2月21日
 * @Description: NIO 改造后的服务端
 */
public class NIOServer {
  public static void main(String[] args) throws IOException {
    // 1. serverSelector负责轮询是否有新的连接,服务端监测到新的连接之后,不再创建一个新的线程,
    // 而是直接将新连接绑定到clientSelector上,这样就不用 IO 模型中 1w 个 while 循环在死等
    Selector serverSelector = Selector.open();
    // 2. clientSelector负责轮询连接是否有数据可读
    Selector clientSelector = Selector.open();

    new Thread(() -> {
      try {
        // 对应IO编程中服务端启动
        ServerSocketChannel listenerChannel = ServerSocketChannel.open();
        listenerChannel.socket().bind(new InetSocketAddress(3333));
        listenerChannel.configureBlocking(false);
        listenerChannel.register(serverSelector, SelectionKey.OP_ACCEPT);

        while (true) {
          // 监测是否有新的连接,这里的1指的是阻塞的时间为 1ms
          if (serverSelector.select(1) > 0) {
            Set<SelectionKey> set = serverSelector.selectedKeys();
            Iterator<SelectionKey> keyIterator = set.iterator();

            while (keyIterator.hasNext()) {
              SelectionKey key = keyIterator.next();

              if (key.isAcceptable()) {
                try {
                  // (1)
                  // 每来一个新连接,不需要创建一个线程,而是直接注册到clientSelector
                  SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
                  clientChannel.configureBlocking(false);
                  clientChannel.register(clientSelector, SelectionKey.OP_READ);
                } finally {
                  keyIterator.remove();
                }
              }

            }
          }
        }
      } catch (IOException ignored) {
      }
    }).start();
    new Thread(() -> {
      try {
        while (true) {
          // (2) 批量轮询是否有哪些连接有数据可读,这里的1指的是阻塞的时间为 1ms
          if (clientSelector.select(1) > 0) {
            Set<SelectionKey> set = clientSelector.selectedKeys();
            Iterator<SelectionKey> keyIterator = set.iterator();

            while (keyIterator.hasNext()) {
              SelectionKey key = keyIterator.next();

              if (key.isReadable()) {
                try {
                  SocketChannel clientChannel = (SocketChannel) key.channel();
                  ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                  // (3) 面向 Buffer
                  clientChannel.read(byteBuffer);
                  byteBuffer.flip();
                  System.out.println(
                      Charset.defaultCharset().newDecoder().decode(byteBuffer).toString());
                } finally {
                  keyIterator.remove();
                  key.interestOps(SelectionKey.OP_READ);
                }
              }

            }
          }
        }
      } catch (IOException ignored) {
      }
    }).start();

  }
}

Why we are reluctant to use JDK native NIO develop it? Everyone can see from the above code, it is really difficult to use! In addition to programming complex and difficult than programming model, it has the following problems people criticized:

  • NIO underlying JDK implemented by epoll, this implementation criticized empty polling bug cause surge cpu 100%
  • After the huge project, self-fulfilling NIO is prone to all kinds of bug, higher maintenance costs, above which a lump of code I can guarantee no bug

Netty appeared largely improved some unbearable problems JDK native NIO present.

3. AIO (Asynchronous I/O)


AIO is NIO 2. Introduced an improved version of NIO 2 NIO in Java 7, it is asynchronous non-blocking IO model . Asynchronous IO is based on the events and callback mechanism to achieve, that is, after the application of the operation will be returned directly, will not plug in there, when background processing is complete, the operating system will notify the appropriate thread for subsequent operations.

AIO is an acronym for asynchronous IO, although the NIO in network operation, provides non-blocking method, but IO NIO or synchronous behavior. For the NIO, the thread when our business is ready IO operations to be notified, and then they were operated by the IO thread itself, IO operation itself is synchronized. (AIO addition to other types of IO are synchronized, this can be explained by the underlying IO threading model, I recommend an article: "Rambling: How to explain what Linux girlfriend five IO model?")

Address reprint: https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/BIO-NIO-AIO.md

Guess you like

Origin blog.csdn.net/weixin_39940206/article/details/94652845