Java NIO

作者: Aiibai | 来源:发表于2018-12-20 20:13 被阅读0次
    基本概念
    • 缓冲区的操作
      用户空间缓冲区
      内核空间缓冲区
      DMA
      用户空间相对于内核空间的限制

    -发散汇聚

    • 虚拟内存
      物理内存与虚拟内存,以及分页

    • 内存页面调度
      也缺失,导致系统调用

    缓存区

    缓冲区就是一个对象,其中有一个数组字段用来存储基本数据元素(除了Boolean),另外有四个属性表示当前读写状态。
    Capacity
    Limit
    Position
    Mark

    0<=Mark<=Position<=Limit<=Capcatiy
    offset

    ByteBuffer
    get
    put
    flip
    rewind
    clear
    hasRemaing
    remaing

    compact
    reset
    mark

    equals
    compareTo

    批量移动

    wrap
    allocate

    复制,视图
    duplicate
    slice
    asReadOnlyBuffer

    字节缓冲区
    allocateDirect

    字节顺序(endian-ness)

    直接缓冲区:JVM 堆外内存
    字节缓冲区域其他缓冲区的区别:
    字节缓冲区的字节顺序是可以改变的,其他缓冲区不行
    只有字节缓冲区可以作为通道的源或目标

    为什么要有直接缓冲区
    非直接字节缓冲区的内存不一定是连续的,而底层IO操作需要连续内存,所以出现了直接缓冲区,即使给通道的是非直接缓冲区,在使用的时候也是会创建一个临时直接缓冲区。
    除了字节缓冲区有直接缓冲区,其他类型的缓冲区都没有直接缓冲区,但是可以作为直接字节缓冲区的视图缓冲区。

    缓冲区视图

    数据元素视图

    通道

    通道主要有两类:文件通道和套接字通道
    FileChannel
    SocketChannel/ ServerSocketChannel / DatagramChannel

    通道既可以是单向的也可以是双向的,具体看实现了那几个接口
    ReadableByteChannel
    WriteableByteChannel

    通过FileInputStream 打开的通道是只读的,即使该通道实现了WriteableByteChannel 接口

     RandomAccessFile file = new RandomAccessFile("abc.csv", "r");
            Charset charset = Charset.forName("UTF-8");
            CharsetDecoder decoder = charset.newDecoder();
    
            FileChannel channel = file.getChannel();
            ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
            CharBuffer charBuffer = CharBuffer.allocate(1024);
            int read = channel.read(buffer);
            while (read != -1) {
                buffer.flip();
                decoder.decode(buffer, charBuffer, false);
                charBuffer.flip();
                System.out.println(charBuffer);
                buffer.compact();
                read = channel.read(buffer);
            }
    

    通道有阻塞和非阻塞模式,只有面向流的 scoketspipes 才能使用非阻塞模式

    将非阻塞和选择器组合实现多路复用IO

    与缓冲区不同,通道不能被重复使用

    通道的 close 方法是阻塞的,具体时间取决于关闭底层IO服务

    关闭通道
    如果一个现在被通道阻塞,中断该线程,对应的通道也会关闭
    此外如果一个线程被中断,再去读通道,通道会关闭

    实现了 InterruptibleChannel 接口的通道,在任何时候都可以关闭,即使有线程在该通道上面阻塞。

    Scatter/Gather (本地矢量IO)

    ScatteringByteChannel GatheringByteChannel

    public class Marketing {
        private static final String DEMOGRAPHIC = "abc.txt";
        // These are just representative; add your own
        private static String[] col1 = {
                "Aggregate", "Enable", "Leverage",
                "Facilitate", "Synergize", "Repurpose",
                "Strategize", "Reinvent", "Harness"
        };
        private static String[] col2 = {
                "cross-platform", "best-of-breed", "frictionless",
                "ubiquitous", "extensible", "compelling",
                "mission-critical", "collaborative", "integrated"
        };
        private static String[] col3 = {
                "methodologies", "infomediaries", "platforms",
                "schemas", "mindshare", "paradigms",
                "functionalities", "web services", "infrastructures"
        };
        private static String newline = System.getProperty("line.separator");
        private static Random rand = new Random();
    
        public static void main(String[] args) throws IOException {
    
            int reps = 10;
    
            if (args.length > 0) {
                reps = Integer.parseInt(args[0]);
            }
    
            FileOutputStream outputStream = new FileOutputStream(DEMOGRAPHIC);
            FileChannel channel = outputStream.getChannel();
    
            ByteBuffer[] buffers = utterBS(reps);
            while (channel.write(buffers) > 0) {
    
            }
            outputStream.close();
            channel.close();
    
            FileInputStream inputStream = new FileInputStream(DEMOGRAPHIC);
            FileChannel channel1 = inputStream.getChannel();
    
            Arrays.stream(buffers).forEach(Buffer::clear);
            while (channel1.read(buffers) > 0) {
    
            }
    
            Charset charset = Charset.forName("UTF-8");
            CharsetDecoder decoder = charset.newDecoder();
            CharBuffer charBuffer;
            for (ByteBuffer readBuffer : buffers) {
                charBuffer = CharBuffer.allocate(readBuffer.limit());
                readBuffer.flip();
                decoder.decode(readBuffer, charBuffer, false);
                charBuffer.flip();
                System.out.println(charBuffer);
            }
    
            System.out.println("All Buffer Data has write to file");
        }
    
        public static ByteBuffer[] utterBS(int howMany) {
            List<ByteBuffer> buffers = new LinkedList<>();
            for (int i = 0; i < howMany; i++) {
                buffers.add(pickRandom(col1, " "));
                buffers.add(pickRandom(col2, " "));
                buffers.add(pickRandom(col3, newline));
            }
    
            ByteBuffer[] byteBuffers = new ByteBuffer[buffers.size()];
            buffers.toArray(byteBuffers);
            return byteBuffers;
        }
    
        public static ByteBuffer pickRandom(String[] strings, String suffix) {
            String string = strings[rand.nextInt(strings.length)];
            byte[] bytes = string.getBytes();
            byte[] bytes1 = suffix.getBytes();
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(bytes.length + bytes1.length);
            byteBuffer.put(bytes);
            byteBuffer.put(bytes1);
            byteBuffer.flip();
            return byteBuffer;
        }
    }
    
    • 文件通道
      阻塞的,相对网络通道延时比较少
      创建方式:
      RandomAccessFile
      FileInputStream
      FileOutputStream

    FileChannel 类保证同一Java 虚拟机上的所有实例看到的某个文件的视图是一直的。
    FileChannel 是线程安全的

    position 表示接下来文件读或写的位置,由channel 和 文件描述符共享

    相关文章

      网友评论

          本文标题:Java NIO

          本文链接:https://www.haomeiwen.com/subject/afykkqtx.html