Netty Getting Started (03) Java NIO introduced -Buffer

NIO Introduction

NIO, can be said that New IO, can also be said to be non-blocking IO, can explain how specific.

NIO 1 in JSR51 inside defined in JDK1.4 introduced, because BolckingIO not support high concurrent network programming, which is Java1.4 previously been criticized reasons. NIO 2 is defined in JSR203 is introduced in JDK1.7, this is JavaNIO entire development process. NIO NIO 2 is not a replacement of the old and new relationships 1 and 2, but a complementary relationship, NIO 2 supplemented with 1 missing something. We can look at two elements:

NIO 1 (this series of articles describes only NIO 1):

Buffers

Channels

Selectors

NIO 2:

Update

New File System API (introduced file system API, which NIO 1 before, in Linux operating documents needs to have read and write access, operation of the various properties, etc., in Java is no way to operate, so here introduced a document API)

Asynchronous IO (that is often said AIO)

BIO and NIO compare the

BIO:

Stream oriented (Stream Oriented) (connection establishment can be obtained when the InputStream and the OutputStream, can be operated by the stream, the stream is not buffered, the efficiency is relatively low)

Blocking IO (Blocking IO)

NIO:

Buffer (Buffer Oriented) (read and written to by Buffer-oriented, to read the data you have to first go Buffer read data, write data must first write data Buffer, and then write the network from Buffer go)

Non-blocking IO (Non Blocking IO) (IO multiplexing model)

Selector (the Selectors)

NIO Buffer learning

Above that, NIO three most important concept is Buffer, Channel, Selector, Buffer buffer is used to put the data, Channel is the channel, the data can be written elsewhere, Selector is a multiplexer, with to implement threads reuse. The following will one by one said. Unlike BIO NIO so simple, even more complicated than it. So I want a piece of learning. The following first learn Buffer.

Buffer is a memory of a nature, data can be written to this memory, data may be read from this memory. JavaNIO defines seven types of Buffer:

file

It can be seen corresponding to several basic types have Buffer (Boolean addition), can store different types of raw data.

Buffer has three core concepts: position, limit, capacity.

file

Best be understood that capacity, on behalf of Buffer capacity Buffer apply for a capacity of 1024, then the capacity is 1024. No special circumstances, capacity will never change. Once the data size of the Buffer reached capacity, needs to be emptied Buffer, in order to write the new value.

It may represent a position that the next operation (read or write) position. A place many people criticized JavaNIO is more complex, the read operation and write operation are mixed, the same operation can be divided into a read mode and a write mode, to the need to manually switch (Flip performed) from the read mode to the write mode, that is to say no separate read and write pointers, the pointer to a position, in write mode, position represents the position of the next writable, in read mode, position represents the position of the next read. When switching the two modes, position will be zero, so that the operation can start from scratch. For example, in write mode, position 0 is written from the 5, then switched to read mode, position becomes 0, start reading from the first.

a position limit represents the maximum limit, in write mode, the representative of the position of the maximum limit is able to write data, this time limit is equal capacity. After switching to the write-read mode, this time limit equal to the actual data in Buffer size because Buffer is not necessarily filled, such write mode Buffer 10 is written into the data capacity of five, then switching to the read mode, Capacity is 10, limit becomes 5, position NATURAL return 0, the value becomes zero.

Create Buffer

Buffer roughly classified into two types, one is the Direct Buffer A is non-direct Buffer, also called HeapBuffer. The following look at the comparison:

Non-direct ByteBuffer

HeapByteBuffer, standard java class (represented on the heap create a Buffer, is an ordinary Java class, stored in the application memory heap Buffer instance)

Maintains a byte [] in the JVM heap

Create a small overhead (heap memory application is very fast, so creating overhead is small)

Copied to a temporary DirectByteBuffer, but the use of temporary buffer cache. Gather write / no temporary buffer cache (that is, as the data in front of the threading model mentioned copy when diverging read, and can not be written directly from the heap buffer is sent directly to the kernel mode, it is necessary to apply for a native in the memory, first data to be copied to the native, and then send)

Automatically GC (garbage collection)

Direct ByteBuffe

The underlying storage in a non-JVM heap, operating through native code (data stored outside the reactor, which is the common memory space outside the JVM, Java through JNI calls nvtive c memory malloc function application, it can not be recovered on behalf of JVM )

-XX:MaxDirectMemorySize=

Create a large overhead (need to call c function application, create a big overhead)

You do not need a temporary buffer copy (data already, can be sent directly in the native)

It needs its own GC, each time you create or release the need to call a System.gc ()

We look at the code, there are two ways to create Buffer, allocate / allocateDirect method, can be seen from the name of each is created on top of which Buffer. Or by means of an array to create (using the warp). Let's use allocate create:

ByteBuffer buffer0 = ByteBuffer.allocate(10);

You can see, it is very simple, and then create a allocateDirect method:

ByteBuffer buffer1 = ByteBuffer.allocateDirect(10);

Then a third, according to create an array:

byte[] bytes = new byte[10];

ByteBuffer buffer2 = ByteBuffer.wrap(bytes);

The time to create an array, the offset may be further provided (location of the new Buffer) and the length:

byte[] bytes2 = new byte[10];

// specified range

ByteBuffer buffer3 = ByteBuffer.wrap(bytes2, 2, 3);

The above four methods to create a common Buffer, we print out four kinds of buffer information, including information on the array, position, limit, capacity three information, as well as the remaining operable space (prints each buffer):

if (buffer0.hasArray()) {

System.out.println("buffer0 array: " + buffer0.array());

System.out.println("Buffer0 array offset: " + buffer0.arrayOffset());

}

System.out.println("Position: " + buffer0.position());

System.out.println("Limit: " + buffer0.limit());

System.out.println("Capacity: " + buffer0.capacity());

System.out.println("Remaining: " + buffer0.remaining());

the hasArray () represents the determination, whether the underlying buffer are stored as an array, as it is true, for HeapByteBuffer, are the underlying array, so weitrue, DirectByteBuffer bottom not stored in an array, it is false, using warp Buffer return is actually created HeapByteBuffer, also in the heap, let's look at the print results buffer0

file

A first two-line printing and offset arrays of arrays, back print out some properties, but also because no operation, so the position is 0, capacity 10 is a matter of course, the last position of the operable time is equal to this limit Capacity, it is 10 operable remaining space is 10, so the results of the above prints. According to the actual situation created out above, buffer0, results buffer1, buffer2 print should be the same, actually also true:

file

buffer3 somewhat different, we created the preconditions set, since the offset is 2, the starting position is the position from the beginning of the 2, 3 become the length is set, the maximum position limit is operable 5 (plus 2 3), since byte2 is created based on the data, so the total capacity is 10, so the capacity or 10, operable to space the remaining natural length is 3, the print result buffer3 follows:

file

Buffer access

And I wrote the code that says how to create Buffer, see below how to access Buffer. Create a buffer:

ByteBuffer buffer = ByteBuffer.allocate(10);

Then look at a printing method Buffer information:

file

Then we print it just created Buffer:

printBuffer(buffer);

Print Results:

file

Message is simple printed above, not explained, see the following the first operation, starts writing data to the Buffer, then print (note that the operation of writing):

file

We write the data to the five Buffer, the Buffer to see how the information changes:

file

5 into a position, other information does not change, the next step, we convert buffer state, the write mode to read mode, and then print:

file

Print Results:

file

Can be seen, after the mode transition, position zero, limit to the end of the data has been written, the same natural Capacity, now reads two elements (Note a read operation):

file

Print Results:

file

Note that the above position changes, let's mark at the current location of the buffer, so after multiple operations, you can also return to the state of the mark:

file

Print result of natural changes nothing:

file

Read two data again:

file

View print the results:

file

Changes position again, return to the position before the following mark:

file

Print Results:

file

The following operation is performed on the compression buffer, the data is copied between the limit position and the start position to the buffer, after copying position = limit -position, limit = capacity, but if there is no data between the limit position and then send it It will not be copied:

file

Print Results:

file

Can be seen that, after compression, the unread data directly moved to the start position, end position moved directly to the data, and switching to the write mode, the position data is equal to the length of the space is not operated, i.e., subtracting the original limit the position, capacity back to the last position in space, we have the following situation buffer:

file

Print Results:

file

We can see, clear directly to the buffer back to the initial state. By several operations above, we can understand the ByteBuffer several pointer change process.

Slice Slice copy Buffer operation

The concept is somewhat similar to the view that the copy operation is a shallow copy, call the method to get an array of new buffers they operate or raw buffer that array, however, through the creation of a new buffer slice operation only original the remaining data in the buffer array, i.e. the original position index buffer when the data slice method calls between the index limit, beyond the scope of this new data buffer created by the slice not to operate. We are given a Buffer, filled with data and then print:

file

Print Results:

file

And manually specify the location and position of the limit:

file

Print Results:

file

Then to position location, segmentation buffer, a new buffer position after segmentation is 0, limit and capacity are a length between the original position and the limit, the new print buffer:

file

Print Results:

file

Out of the new cycle segmentation buffer, to read out one by one, and then multiplied by 11, and then into the original position:

file

Print Results:

file

Because it can be seen that the read operation position change occurs, manual positioning of the original start and end positions of the buffer, reading the print cycle each of the original data in the buffer, the buffer was found to modify the segmentation while also modified the original buffer, described shallow copy slice is:

file

Print Results:

file

Duplicate Copy Buffer operation

Also a shallow copy Duplicate represented, that is, drinking only copy, object instance or a point. We create a buffer, slowing down the data and then print:

file

Print Results:

file

Converting read-write, then the print:

file

Print Results:

file

3 position to the manual positioning and 6, mark once, and then individually positioned to position 5:

file

Print Results:

file

Shallow copy, including the original position and limit position but also with the copy over the original position of the reset buffer empty, and the limit position (note that only clear pointer is reset, the data also):

file

Copy out of position and limit position or the last position before blanking, print the results:

file

Copy also cleared out of the position and limit position is also returned to the leftmost and rightmost:

file

Print Results:

file

asReadOnlyBuffer operation Duplicate the same, but the former is read-only.

Shortcoming

One reason NIO Buffer is in charge of programming complexity, Buffer pointer come and go quite complex, but already a pointer, read-write mode as well as interchangeable, this should carefully control their own job. Mode mistake will be a big problem.

Code address: https: //gitee.com/blueses/netty-demo 02

This article from the blog article multiple platforms OpenWrite release!

Guess you like

Origin juejin.im/post/5e1c2144f265da3e0163e5a4