【NIO】解读 java.nio.Buffer

目录

Part 1. BackGroud

Part 2. Doc Guide

1. What's the buffer?

2. What's the essential feature?

3. how to operate buffer?

4. Something you may wanna know

Part 3. Analysis as container and  'Read & Write'  feature

Part 4. Demo Train



 

Part 1. BackGroud

Target: Learn nio buffer by it's java doc.

Premise:  You should have some  basic knowledge of NIO.

“Non-Blocking I/O”, also called“New I/O”in java, of which the core conceptions are "Selector", "Channel", "Buffer". 

This article focus on the analysis of buffer:

【NIO】解读 java.nio.Buffer_第1张图片

 

Part 2. Doc Guide

Open the class file "java.nio.Buffer" like this:

【NIO】解读 java.nio.Buffer_第2张图片

Target before analysis:  By reading this doc, asking yourself several questions like:

 “what’s buffer”、“why buffer”、"what's core conception"、"how to use buffer"……

 

1. What's the buffer?

A container for data of a specific primitive type.
A buffer is a linear, finite sequence of elements of a specific primitive type.

 

2. What's the essential feature?

1) core properties:

The essential properties of a buffer are its:

1.capacity:

A buffer's capacity is the number of elements it contains. The capacity of a buffer is never negative and never changes.

2.limit:

A buffer's limit is the index of the first element that should not be read or written. A buffer's limit is never negative and is never greater than its capacity.

3.position:

A buffer's position is the index of the next element to be read or written. A buffer's position is never negative and is never greater than its limit.

 

2) Buffer's component

There is one subclass of this class for each non-boolean primitive type

Ok,  this pic  above is from https://blog.csdn.net/napo_leon/article/details/24696779.

And this is the structure of ByteBuffer:

【NIO】解读 java.nio.Buffer_第3张图片

 

3) Invariants

The following invariant holds for the mark, position, limit, and capacity values:

[0 <= mark <= position <= limit <= capacity]

A newly-created buffer always has a position of zero and a mark that is undefined. The initial limit may be zero, or it may be some other value that depends upon the type of the buffer and the manner in which it is constructed. Each element of a newly-allocated buffer is initialized to zero.

 

3. how to operate buffer?

1) Transferring data

A buffer's mark is the index to which its position will be reset when the reset method is invoked. The mark is not always defined, but when it is defined it is never negative and is never greater than the position. If the mark is defined then it is discarded when the position or the limit is adjusted to a value smaller than the mark. If the mark is not defined then invoking the reset method causes an InvalidMarkException to be thrown.

2) Marking and resetting

A buffer's mark is the index to which its position will be resetwhen the reset method is invoked. The mark is not always defined, but when it is defined it is never negative and is never greater than the position. If the mark is defined then it is discarded when the position or the limit is adjusted to a value smaller than the mark. If the mark is not defined then invoking the reset method causes an InvalidMarkException to be thrown.

3) Clearing, flipping, and rewinding

In addition to methods for accessing the position, limit, and capacity values and for marking and resetting, this class also defines the following operations upon buffers:

1 clear() makes a buffer ready for a new sequence of channel-read or relative put operations: It sets the limit to the capacity and the position to zero.

2 flip() makes a buffer ready for a new sequence of channel-write or relative get operations: It sets the limit to the current position and then sets the position to zero.

3 rewind() makes a buffer ready for re-reading the data that it already contains: It leaves the limit unchanged and sets the position to zero.

 

4. Something you may wanna know

1) Read-only buffers

Every buffer is readable, but not every buffer is writable. The mutation methods of each buffer class are specified as optional operations that will throw a ReadOnlyBufferException when invoked upon a read-only buffer. A read-only buffer does not allow its content to be changed, but its mark, position, and limit values are mutable. Whether or not a buffer is read-only may be determined by invoking its isReadOnly method.

2) Thread safety

Buffers are not safe for use by multiple concurrent threads. If a buffer is to be used by more than one thread then access to the buffer should be controlled by appropriate synchronization.

3) Invocation chaining

Methods in this class that do not otherwise have a value to return are specified to return the buffer upon which they are invoked. This allows method invocations to be chained; for example:

'''

b.flip();

b.position(23);

b.limit(42);

'''

the sequence of statements can be replaced by the single, more compact statement:

'''

b.flip().position(23).limit(42);

'''

“The most efficient and accurate way to understand a tool and component is to read its official website, java doc, source code”,By re-organizing the doc of Buffer, the definition, role, attributes, and common methods of the core of the buffer are already very clear. 

What Vincent himself is cultivating that the habit of reading native doc and share it with you.

 

 

Part 3. Analysis as container and  'Read & Write'  feature.

1. Basic operation and the change of "position、limit and capacity". 

/**
* buffer基础操作:
*
* 

* 通过allocate()、 put()、 get()、 flip()、 rewind() 方法,观察 position、limit、capacity 变化,了解buffer工作原理 *

* * @param args * @throws Exception */ public static void main(String[] args) throws Exception{ byte[] bytes = "hello!".getBytes("utf-8"); // 初始化 allocate() 分配初始化大小 ByteBuffer buffer = ByteBuffer.allocate(10); printInfo(buffer, "init buffer"); // 写入 put 向buffer中写入数据 for (byte b : bytes) { buffer.put(b); } printInfo(buffer, "put buffer"); // 翻转 flip() 读写状态转换,limit、capacity变化 buffer.flip(); printInfo(buffer, "flip buffer"); // 输出 get() 获取buffer内容 while (buffer.hasRemaining()) { System.out.println(buffer.get()); } printInfo(buffer, "get buffer"); // 重读 rewind() 将position置0 buffer.rewind(); printInfo(buffer, "rewind buffer"); // 验证是否可以重读 System.out.println((char)buffer.get()); printInfo(buffer, "reread buffer"); } static void printInfo(ByteBuffer buffer, String desc) { System.out.println("=== " + desc + " ==="); System.out.println("the position is: " + buffer.position() + "; the limit is:" + buffer.limit() + "; the capacity is:" + buffer.limit()); System.out.println(""); }

For the process like this:

1. init buffer

the position is: 0;  the limit is:10;  the capacity is:10

【NIO】解读 java.nio.Buffer_第4张图片

 

2. put buffer

the position is: 6;  the limit is:10;  the capacity is:10

【NIO】解读 java.nio.Buffer_第5张图片

 

3. flip buffer

the position is: 0;  the limit is:6;  the capacity is:6

【NIO】解读 java.nio.Buffer_第6张图片

 

4. get buffer

the position is: 6;  the limit is:6;  the capacity is:6

【NIO】解读 java.nio.Buffer_第7张图片

 

5. rewind buffer

the position is: 0;  the limit is:6;  the capacity is:6

【NIO】解读 java.nio.Buffer_第8张图片

 

6. reread buffer

the position is: 1;  the limit is:6;  the capacity is:6

【NIO】解读 java.nio.Buffer_第9张图片

 

 

Part 4. Demo Train

After summarizing the buffer's feature in part 2 and showing the data process in part 3,  I will show several demo to better understanding of it.

1 Basic intput && output 

/**
* nio buffer 输入、输出
*
* @Author : Vincent
* @Date: 2020-06-27 11:22
*/
public class BuferTest1 {

    public static void main(String[] args) {
        IntBuffer buffer = IntBuffer.allocate(10);
        // 输入 10  个
        for (int i = 0; i < buffer.capacity(); i++) {
            int randomNum = new SecureRandom().nextInt(20);
            buffer.put(randomNum);
        }
        // 输入、输出 转换
        buffer.flip();
        // 输出 10 个
        while (buffer.hasRemaining()) {
            System.out.println(buffer.get());
        }
    }
}

2 Data type && Sequence

/**
* 支持多数据类型存储,获取时顺序获取
*
* @Author : Vincent
* @Date: 2020-07-04 09:37
*/
public class BuferTest2 {

    /**
     * ByteBuffer提供存入其他类型api,最终转为byte[]
     *
     * 

* 存入顺序,必须与获取顺序对应 *

* * @param args */ public static void main(String[] args) { ByteBuffer buffer = ByteBuffer.allocate(64); buffer.putInt(3); buffer.putDouble(1.0); buffer.putLong(123123l); buffer.putChar('a'); buffer.putShort((short) 4); buffer.flip(); System.out.println(buffer.getInt()); System.out.println(buffer.getDouble()); System.out.println(buffer.getLong()); System.out.println(buffer.getChar()); System.out.println(buffer.getShort()); } }

3 Slice operaton

/**
* 
*
* @Author : Vincent
* @Date: 2020-07-04 09:42
*/
public class BuferTest3 {

    /**
     * slice 分片,参考slice api
     *
     * 

* Creates a new byte buffer whose content is a shared subsequence of this buffer's content. * * 1.The new buffer will start at this buffer's current position. * 2.Changes to this buffer's content will be visible in the new buffer, and vice versa; * 3.The two buffers' position, limit, and mark values will be independent. *

* * @param args */ public static void main(String[] args) { ByteBuffer buffer = ByteBuffer.allocate(10); //buffer初始化 for (int i = 0; i

4 Writable & readable 's single transefer to read-only buffer

/**
* 普通buffer可转只读buffer; 但只读buffer不能转换为读写buffer.
*
* @Author : Vincent
* @Date: 2020-07-04 10:05
*/
public class BuferTest4 {

    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocate(10);

        //buffer初始化
        for (int i = 0; i

5 The apply of scatter and gather

public class BuferTest5 {

    /**
     * Scattering 与 Gathering 的应用
     *
     * 

* 可用 telnet 或 nc 测试 *

* * @param args */ public static void main(String[] args) throws Exception{ // nio 监听端口 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); InetSocketAddress address = new InetSocketAddress(8899); serverSocketChannel.socket().bind(address); // 定义消息长度9,分散给3个buffer int mesLength = 2 + 3 + 4; ByteBuffer[] buffers = new ByteBuffer[3]; buffers[0] = ByteBuffer.allocate(2); buffers[1] = ByteBuffer.allocate(3); buffers[2] = ByteBuffer.allocate(4); SocketChannel socketChannel = serverSocketChannel.accept(); while (true) { //读 buffer int bytesRead = 0; //读不够9个字节时,不执行后续流程 while (bytesRead < mesLength) { long r = socketChannel.read(buffers); bytesRead += r; Arrays.asList(buffers).stream() .map((buffer) -> "position:" + buffer.position() + ", limit:" + buffer.limit()) .forEach(System.out::println); } //读写转换 Arrays.asList(buffers).forEach(buffer -> { buffer.flip(); }); //写 buffer long bytesWritten = 0; while (bytesWritten < mesLength) { long r =socketChannel.write(buffers); bytesWritten += r; } //buffer归位 Arrays.asList(buffers).forEach(buffer -> buffer.clear()); System.out.println("bytesRead:" + bytesRead + ", bytesWrite:" + bytesWritten + ",messageLength " + mesLength); } } }

 

你可能感兴趣的:(java,nio,buffer,后端)