Netty 学习笔记四 了解缓冲区

了解缓冲区

NIO核心对象

在NIO中,缓冲区、选择器、通道是三个核心的对象。本文重点介绍Buffer缓冲区。

1. Buffer 简介

缓冲区可以理解为了一个基于数组的容器对象,在NIO库中,所有数据都是在缓冲区处理的。当要读取数据时,就把数据读到缓冲区,要写入数据时,也是把数据写到缓冲区。这与面向流的I/O系统中,所有数据都是直接写入或从流中读取是类似的。
在NIO中,缓冲区数据类型从抽象类Buffer继承,对于Java的基本类型,会有具体的Buffer类型与之对应,如:

  • ByteBuffer
  • LongBuffer
  • DoubleBuffer
  • CharBuffer
  • FloatBuffer
  • IntBuffer
  • ShortBuffer
  • MappedByteBuffer
    最常用的可能就是ByteBuffer了。

2. 一段简单的Buffer使用例子

package org.example;

import java.nio.IntBuffer;

public class App {
    public static void main(String[] args) {
        // 分配一个32字节的缓冲区,position=0
        IntBuffer buffer = IntBuffer.allocate(Integer.SIZE);
        for (int i = 0; i < buffer.capacity(); ++i) {
            int j = i * i;
            // 缓冲区放一个值
            buffer.put(j);
        }
        // 重置缓冲区,position设为0
        buffer.flip();
        while (buffer.hasRemaining()) {
            // 每次读取后,position会自动指到下一个位置 
            int j = buffer.get();
            System.out.print(j + " ");
        }
    }
}

3. Buffer的重要属性

position

下一个将要被写入或读取的元素位置索引,当get()/put()的时候会自动更新值。

limit

缓冲区的限制,它的值小于或等于capacity。

capacity

最大容量。

mark

在缓冲区的位置设置标记。

4. 缓冲区的分配

allocate 用于创建一个指定大小的缓冲区,它的参数是数组大小,也可以使用wrap直接封装一个数组:

byte array[] = new byte[10];
ByteBuffer buffer2 = ByteBuffer.wrap(array);

5. 子缓冲区

可以在一个缓冲区上开辟一段子缓冲区,便于操作。

package org.example;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

public class App {
    public static void main(String[] args) {
        IntBuffer buffer = IntBuffer.allocate(8);
        for(int i=0;i<buffer.capacity();++i){
            buffer.put(i);
        }
        //创建子缓冲区
        buffer.position(4);
//        buffer.limit(5);
        IntBuffer slice = buffer.slice();

        // 把一个位置的平方
        int tmp = slice.get(0);
        tmp = tmp*tmp;
        slice.put(0, tmp);
        buffer.position(0);
        buffer.limit(buffer.capacity());
        while(buffer.remaining()>0){
            System.out.println(buffer.position() + " = " + buffer.get());
        }
    }
}

返回值:

0 = 0
1 = 1
2 = 2
3 = 3
4 = 16
5 = 5
6 = 6
7 = 7

6. 只读缓冲区

buffer.asReadOnlyBuffer

7. 直接缓冲区

在虚拟机内存外开辟的内存,IO操作直接进行,不再对其进行复制,但创建和销毁开销大。

8. 内存映射

java中传统的文件操作使用File的I/O操作,JVM发起read()、write(),会调用操作系统的内核,当中存在数据传输。
从jdk1.4开始,提供了MappedByteBuffer,用于帮助建立一个从JVM空间到OS文件系统页的映射的虚拟内存。这种方式避免了因为拷贝文件内容的带来的开销。
OS使用虚拟内存在内核空间之外缓存文件,可以被非内核进行所共享。java直接映射文件页到MappedByteBuffer,然后处理文件,不需要将其加载到JVM里面。

上一篇:Java Socket 编程


下一篇:Java开发技术之NIO缓冲区的概念分析