IO stream - BIO, NIO, AIO

Keywords: Programming Java network socket

IO, often collaborative I/O, is the abbreviation of Input/Output, that is, Input/Output. At present, there are three types of IO coexisting. They are BIO, NIO and AIO. Before we get to know IO, let's look at the concepts.

Related concepts

Flow oriented and buffer oriented

The first big difference between Java IO and NIO is that IO is stream oriented and NIO is buffer oriented. Java IO stream oriented means that one or more bytes are read from the stream at a time, until all bytes are read, and they are not cached anywhere. In addition, it cannot move data in the stream back and forth. If you need to move the data read from the stream back and forth, you need to cache it into a buffer first. Java NIO's buffer oriented approach is slightly different. The data is read to a buffer that it later processes and can move back and forth in the buffer if necessary. This increases the flexibility of the process. However, you also need to check that the buffer contains all the data you need to process. Also, make sure that when more data is read into the buffer, do not overwrite the unprocessed data in the buffer.

Synchronous asynchronous (destination)

Synchronization and asynchrony are for the interaction between the application and the kernel.

  1. Synchronization: after performing an operation, wait for the result before proceeding with subsequent operations.
  2. Asynchrony: after performing an operation, you can perform other operations, and then wait for the notification to come back to perform the unfinished operation.

Blocking and non blocking IO (implementation mode)

Blocking and non blocking are different ways for processes to access data according to the ready state of IO operations

Various streams of Java IO are blocked. This means that when a thread calls read() or write(), the thread is blocked until some data is read or fully written. The thread cannot do anything more during this time. The non blocking mode of Java NIO enables a thread to send a request to read data from a channel, but it can only get the currently available data. If there is no data available at present, it will not get anything, rather than keep the thread blocked, so until the data becomes readable, the thread can continue to do other things. The same is true for non blocking writes. A thread requests to write some data to a channel, but does not need to wait for it to write completely. This thread can do other things at the same time. Threads usually use non blocking IO idle time to perform IO operations on other channels, so a single thread can now manage multiple input and output channels.

  1. Blocking: after the process communicates a task to the CPU, it waits for the CPU to complete processing before performing subsequent operations.
  2. Non blocking: after the process communicates any information to the CPU, continue to process the subsequent operations, and then ask whether the previous operations are completed after the cut-off time. This process is also called polling

Selectors

Java NIO's selector allows a single thread to monitor multiple input channels. You can register multiple channels to use a selector, and then use a single thread to "select" channels: these channels already have input that can be processed, or select channels that are ready to be written. This selection mechanism makes it easy for a single thread to manage multiple channels.

BIO (synchronous blocking)

The full name of BIO block IO is a synchronous and blocking communication mode. It is a more traditional communication mode with simple mode and convenient use. But the concurrent processing ability is low, the communication time-consuming, and depends on the network speed. BIO processes data in the form of stream. An input stream generates one byte of data, and an output stream consumes one byte of data.

//Initializing objects
User1 user = new User1();
user.setName("hollis");
user.setAge(23);
System.out.println(user);

//Write Obj to file
ObjectOutputStream oos = null;
try {
    oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
    oos.writeObject(user);
} catch (IOException e) {
    e.printStackTrace();
} finally {
    IOUtils.closeQuietly(oos);
}

//Read Obj from file
File file = new File("tempFile");
ObjectInputStream ois = null;
try {
    ois = new ObjectInputStream(new FileInputStream(file));
    User1 newUser = (User1) ois.readObject();
    System.out.println(newUser);
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} finally {
    IOUtils.closeQuietly(ois);
    try {
        FileUtils.forceDelete(file);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

//Initializing objects
User1 user = new User1();
user.setName("hollis");
user.setAge(23);
System.out.println(user);

//Write Obj to File
ObjectOutputStream oos = null;
try {
    oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
    oos.writeObject(user);
} catch (IOException e) {
    e.printStackTrace();
} finally {
    IOUtils.closeQuietly(oos);
}

//Read Obj from file
File file = new File("tempFile");
ObjectInputStream ois = null;
try {
    ois = new ObjectInputStream(new FileInputStream(file));
    User1 newUser = (User1) ois.readObject();
    System.out.println(newUser);
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} finally {
    IOUtils.closeQuietly(ois);
    try {
        FileUtils.forceDelete(file);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

NIO (synchronous non blocking)

NIO has the same function and purpose as the original I/O. the most important difference between them is the way of data packaging and transmission. NIO processes data in blocks. Each operation generates or consumes a data block in one step. Processing data by block is much faster than processing data by (streaming) bytes. But block oriented I/O lacks the elegance and simplicity of stream oriented I/O.

static void readNIO() {
    String pathname = "C:\\Users\\adew\\Desktop\\jd-gui.cfg";
    FileInputStream fin = null;
    try {
        fin = new FileInputStream(new File(pathname));
        FileChannel channel = fin.getChannel();

        int capacity = 100;// byte
        ByteBuffer bf = ByteBuffer.allocate(capacity);
        int length = -1;

        while ((length = channel.read(bf)) != -1) {
             bf.clear();
             byte[] bytes = bf.array();
             System.out.write(bytes, 0, length);
             System.out.println();
        }

        channel.close();

     } catch (FileNotFoundException e) {
            e.printStackTrace();
     } catch (IOException e) {
            e.printStackTrace();
     } finally {
            if (fin != null) {
                try {
                    fin.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
     }
}

static void writeNIO() {
    String filename = "out.txt";
    FileOutputStream fos = null;
    try {

      fos = new FileOutputStream(new File(filename));
      FileChannel channel = fos.getChannel();
      ByteBuffer src = Charset.forName("utf8").encode("Hello hello hello hello hello");
      int length = 0;

      while ((length = channel.write(src)) != 0) {
            System.out.println("Write length:" + length);
      }

    } catch (FileNotFoundException e) {
          e.printStackTrace();
    } catch (IOException e) {
          e.printStackTrace();
    } finally {
          if (fos != null) {
              try {
                  fos.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
    }
}

AIO (asynchronous non blocking)

Based on NIO, a new concept of asynchronous channel is introduced, and the realization of asynchronous file channel and asynchronous socket channel is provided.

public class ReadFromFile {
  public static void main(String[] args) throws Exception {
    Path file = Paths.get("/usr/a.txt");
    AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);

    ByteBuffer buffer = ByteBuffer.allocate(100_000);
    Future<Integer> result = channel.read(buffer, 0);

    while (!result.isDone()) {
      ProfitCalculator.calculateTax();
    }
    Integer bytesRead = result.get();
    System.out.println("Bytes read [" + bytesRead + "]");
  }
}
class ProfitCalculator {
  public ProfitCalculator() {
  }
  public static void calculateTax() {
  }
}

public class WriteToFile {

  public static void main(String[] args) throws Exception {
    AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(
        Paths.get("/asynchronous.txt"), StandardOpenOption.READ,
        StandardOpenOption.WRITE, StandardOpenOption.CREATE);
    CompletionHandler<Integer, Object> handler = new CompletionHandler<Integer, Object>() {

      @Override
      public void completed(Integer result, Object attachment) {
        System.out.println("Attachment: " + attachment + " " + result
            + " bytes written");
        System.out.println("CompletionHandler Thread ID: "
            + Thread.currentThread().getId());
      }

      @Override
      public void failed(Throwable e, Object attachment) {
        System.err.println("Attachment: " + attachment + " failed with:");
        e.printStackTrace();
      }
    };

    System.out.println("Main Thread ID: " + Thread.currentThread().getId());
    fileChannel.write(ByteBuffer.wrap("Sample".getBytes()), 0, "First Write",
        handler);
    fileChannel.write(ByteBuffer.wrap("Box".getBytes()), 0, "Second Write",
        handler);

  }
}

summary

BIO NIO AIO
One connection one thread: that is, the client has a connection
When receiving a request, the server needs to start a
Thread processing, if this connection does not
Anything can cause unnecessary thread overhead,
Of course, it can be improved through the thread pool mechanism.
One request one thread: that is, the client sends
Connection requests for are registered with the multiplexer
On, the multiplexer polls to connect I/O please
A thread is started for processing only when the time is required.
One valid request one thread: customer
The I/O requests of the end are completed by the OS first
Notify the server application to start the line again
Process,
Synchronize and block Synchronous non blocking Asynchronous non blocking
A fixed architecture with a small number of connections Architecture with many connections and short connections (light operation) Architecture with many connections and long connections (reoperation)
Flow oriented Buffer oriented  
nothing selector  

Posted by derwert on Mon, 23 Dec 2019 05:05:12 -0800