• Java nio


    近期有用到 netty  ,netty中使用到了nio。做个记录 

    通常用到i/o的情况:

    文件存储

    网络i/o

    nio升级的地方对于网络i/o,单线程就可以处理大量请求。

    1 内存空间,什么是用户空间,什么是内核空间。

    早期 操作系统 比如,4g的内存。并没区分 用户空间 和内核空间,但是这种设计时常会导致,系统频频奔溃 因为用户操作千奇百怪 容易出错。

    于是操作系统提出了,用户空间 和 内核空间 (用户态的程序不能随意操作内核地址空间,这样对操作系统具有一定的安全保护作用 ,对cpu的操作指令分为 r0 - r3)。

    比如 4g的内存,设置其中1 g 为内核空间。权限等级为 r0 ,此内核空间是受保护的空间,供操作系统内核使用。其他3g设置为用户空间,权限等级为r3,此空间是提供给用户使用的,不受保护。

    2 用户态到内核态的切换。

    如上图所示,所有系统资源的管理都是在内存空间进行的,也就是在内核态去做的,那我们应用程序需要访问磁盘,新建一个线程都需要通过系统调用接口,完成从用户态到内存态的切换。

    例如:

    Java 中需要新建一个线程,new Thread( Runnable ...) 之后调用 start() 方法时, 看Hotspot Linux 的JVM 源码实现,最终是调pthread_create 系统方法来创建的线程,这里会从用户态切换到内核态完成系统资源的分配,线程的创建

    3 一张普通的IO处理的流程图:

    实际上代码可以操作的部分就只有第一步。

    FileReader fileReader = new FileReader("C:\\Users\\kevin\\Desktop\\新建文本文档.txt");
    // 带缓冲的流读取,默认缓冲区8k
    BufferedReader br = new BufferedReader(fileReader);
    String line;
    while ((line = br.readLine()) != null) {
    System.out.println(line);
    }

    备注:某些流 (例如 FileInputStream 和 Url 类的 openStream 方法返回的输入流)可以从文件和其他外部位置上获得字节 ,而其他的流 (例入DataInputStream 和 PrintWriter)可以将字节组装到更有用的数据类。 所以先创建 一个FileInputStream 然后将其传递给 DataInputStream 。上面例子就是这样 组合运用流。

     这里我们是  创建了一个带缓存区的流。带缓冲区的输入流在流中读入字符时 ,不会每次都对设备进行访问。当缓冲区为空时 ,会向缓冲区 读入一个新的数据快

    BufferedReader br = new BufferedReader(fileReader);

    4 什么是bio 什么是nio 

    BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善 (伪nio ,实际中 如果io请求量大 则无用。)。 

    NIO:同步非阻塞式IO,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。 

    AIO(NIO.2):异步非阻塞式IO,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。 (这里不讨论)

    bio的实现:

    FileReader fileReader = new FileReader("C:\\Users\\kevin\\Desktop\\新建文本文档.txt");
    // 带缓冲的流读取,默认缓冲区8k
    BufferedReader br = new BufferedReader(fileReader);
    String line;
    while ((line = br.readLine()) != null) {
    System.out.println(line);
    }

    一行一行读,上一行读完 才可以读下一行,没读完则阻塞

    nio的实现:

    File file = new File("data.txt");
    FileOutputStream outputStream = new FileOutputStream(file);
    FileChannel channel = outputStream.getChannel();
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    String string = "java nio";
    buffer.put(string.getBytes());
    buffer.flip(); //此处必须要调用buffer的flip方法
    channel.write(buffer);
    channel.close();
    outputStream.close();

    多了两个概念,channel ,buffer

    5什么是channel  什么是buffer 

    Channel:和IO中的Stream(流)是差不多一个等级的。只不过Stream是单向的,譬如:InputStream, OutputStream.而Channel是双向的,既可以用来进行读操作,又可以用来进行写操作。

    备注:InputStream 和 OutputStream 是面向字节的,所以从抽象类 Reader 和 Writer 中继承出来一个专门用于处理Unicode 字符的单独类层次结构

     主要实现类:

    SocketChannel:
    • SocketChannel主要用途用来处理网络I/O的通道
    • SocketChannel是用来连接Socket套接字
    FileChannel:
    • FileChannel主要用途出来文件I/O的通道

     主要代码:

    //读
    public abstract int read(ByteBuffer dst, long position) throws IOException;
    //写
    public abstract int write(ByteBuffer src, long position) throws IOException;

    多路复用:多个channel 注册到一个selector ,selector 轮询监听每个channel 的状态,有变化则调用(poll)。理论是注册的channel是无上限,这样只需要使用一个线程去处理selector ,多个channle 复用一个线程。

                     epoll 模型再poll上做了改进,设置了回调函数,不用轮询了。

    
    
    ByteBuffer:本质是一个继承了Buffer 的byte数组
    final byte[] hb;

    主要代码:


    public abstract class Buffer {
    //
    private int mark = -1;
    // 当前缓存标记
    private int position = 0;
    private int limit;
    private int capacity;

    public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
    }
    public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
    }
    public final Buffer mark() {
    mark = position;
    return this;
    }
    final void truncate() { // package-private
    mark = -1;
    position = 0;
    limit = 0;
    capacity = 0;
    }
    }


    通过 flip() 方法将,写模式变成了读模式。确实不错

     nio中 所有数据的传输 都是通过 buffer 来进行。好处是可以不用阻塞

    6 netty是一个优秀的nio框架

  • 相关阅读:
    Oracle数据库面试题【转载】
    年龄计算周岁
    丈夫的权力与妻子的职业水平
    JDK 8 and JRE 8 Supported Locales
    一笔画 奇点 偶点
    流水行船问题
    PL/SQL LOOP SAMPLE
    OpenCV——识别各省份地图轮廓
    OpenCV——轮廓面积及长度计算
    树莓派3安装opencv2程序无法运行
  • 原文地址:https://www.cnblogs.com/publicmain/p/16336988.html
Copyright © 2020-2023  润新知