Java NIO ByteBuffer using research and source code

A conclusion

  System is Java NIO ByteBuffer base class, all of the data carrier interoperates with the Channel are based ByteBuffer as the data (i.e., buffer). Is the underlying ByteBuffer byte array, the data write operation is implemented to the buffer buffers the like and a multiplexing four important member variables (mark, limit, position, capacity). There are ways to apply ByteBuffer buffer memory (array) of two types, namely external heap memory and heap memory, external memory heap which has a strong performance, but need to be handled with care, you can be assured of heap memory to the JVM management. It also should be noted that it is important ByteBuffer not thread-safe.

Two, API research

  Learn new things always go back to its essence, first consider the following questions:

  If you use an array as a buffer, the buffer want to reuse what need to do?

  Here we write IO to block the file will be described (the code below)

  We created a new array as a buffer, read the file when the buffer is to continue to write and record the actual number of bytes read and write the number of bytes actually read byteOutputStream.

  As can be seen in order to use an array as a buffer First, we need at least the following data

    1. The buffer size (buffer.length)

    2. The number of bytes available in the buffer (i.e. readLength, it is impossible to read the data each time to fill the entire buffer )

    Further, since data can be read InputStream specified segment buffer, and therefore the number of bytes available in the buffer is actually an array index value (default 0) plus the length of the actual number of bytes read Composition of.

 1     public static void main() throws IOException {
 2         byte[] buffer = new byte[1024];
 3         ByteOutputStream byteOutputStream = new ByteOutputStream();
 5         File file = new File("D:/tmp/test");
 6         FileInputStream inputStream = new FileInputStream(file);
 7         int readLength = 0;
 8         while ((readLength = != 0){
 9             // do something
10             byteOutputStream.write(buffer,0,readLength);
11         }
12         inputStream.close();
13         System.out.println(new String(byteOutputStream.getBytes()));
14     }

  Therefore, ByteBuffer can be reused as a buffer zone, also use arrays as the underlying buffer whose core members are the following four variables

    // Invariants: mark <= position <= limit <= capacity
    private int mark = -1;
    private int position = 0;
    private int limit;
    private int capacity;

  mark mark

  position location, where the location of the current pointer array, i.e., the next reading position where the pointer \ write array elements

  Restriction buffer limit, the first should not \ read data position (corresponding to readLength) is written to this buffer (default equal capacity)

  The actual size of the buffer capacity (corresponding buffer.length)

  So ByteBuffer API that mainly around around four member variables carried out.


  1. remaining illustrate (the method used to obtain the size of the remaining elements)

    public final int remaining() {
        return limit - position;


      (Picture from "NIO and Socket Programming Guide")

    At this time, as shown in FIG capacity = 8, limit = 6, position = 2, in order to read data at this time is illustrated as an example there are four elements available for reading.


  2.ByteBuffer multiplexing implementation

  Reference example blocking read and write files can be re-bound to determine the variables associated with the reset ByteBuffer, reset the different variables have different effects.

  For example, after writing data to the ByteBuffer, when data is read again to write necessarily need to know the actual length of the data ( limit and does not vary with the write data, limit represents the limit buffer ), and the array pointer moves to a position 0.

  filp approach is viable to do this, which achieve the following:

public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;

  To restore the state of the buffer, it can directly call clear, but the method does not clear the data in the buffer

public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;

  If the process of reading data (in this case postion has changed) wants to read the data again from the postion can simply reset, rewind method may be used, which mark is reset to -1.

public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;

  3 .Mark about

  From the design ByteBuffer not support a buffer random access (RandomAccess), and write or read data when an array of pointers can only move forward, but in some scenarios we may need for a data segment content read repeatedly, at this time only needs to perform a marking operation on the specified position for the time needed to move the pointer to the marker position.

  mark method shown below, but the temporary position, and does not change the position of the pointer.

    public final Buffer mark() {
    mark = position;
    return this;

  So if you want to return to the position it is necessary to perform the reset method.

public final Buffer reset() {
    int m = mark;
    if (m < 0)
        throw new InvalidMarkException();
    position = m;
    return this;

  Since the mark default value -1, so the method is not performed if the mark will throw an exception.







Guess you like