Netty框架基础----NIO非阻塞式IO介绍,示意图和demo实例

一.NIO介绍


  • Java NIO 全称 java non-blocking IO,是指 JDK 从 JDK1.4 开始提供的新 API。Java 提供了一系列改进的输入/输出的新特性,被统称为 NIO(即 New IO),是同步非阻塞的

  • NIO 相关类都被放在 java.nio 包及子包下,并且对原 java.io 包中的很多类进行改写
    在这里插入图片描述

  • NIO 有三大核心部分:Channel(通道),Buffer(缓冲区), Selector(选择器)

NIO是 面向缓冲区 ,或者面向 块 编程的。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性,使用它可以提供非阻塞式的高伸缩性网络。满足我们在高并发环境下的生产需求。


二.NIO和BIO比较

  • BIO 以流的方式处理数据,而 NIO 以块的方式处理数据,块 I/O 的效率比流 I/O 高很多
  • BIO 是阻塞的,NIO 则是非阻塞的
  • BIO基于字节流和字符流进行操作,而 NIO 基于 Channel(通道)和 Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择器)用于监听多个通道的事件(比如:连接请求,数据到达等),因此使用单个线程就可以监听多个客户端通道

三.NIO三大核心的原理示意图

在这里插入图片描述

  1. 每个channel 都会对应一个Buffer
  2. Selector 对应一个线程, 一个线程对应多个channel(连接)
  3. 程序切换到哪个channel 是由事件Event决定的, Event 是一个重要的概念。Selector 会根据不同的事件,在各个通道上切换
  4. 数据的读取写入是通过Buffer, 这个和BIO , BIO 中要么是输入流,或者是 输出流, 不能双向,但是NIO的Buffer 是可以读也可以写, 需要 flip 方法切换

缓冲区(Buffer)
  • 缓冲区(Buffer):缓冲区本质上是一个可以读写数据的内存块,可以理解成是一个容器对象(含数组),该对象提供了一组方法,可以更轻松地使用内存块,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况。Channel 提供从文件、网络读取数据的渠道,但是读取或写入的数据都必须经由 Buffer
    在这里插入图片描述
Buffer顶层抽象类的重要变量

所有继承Buffer的子类都有这四个参数
在这里插入图片描述

Buffer基本函数用法示例

put:写数据
get:读数据
flip():读写切换
position(int i):定位buffer

public static void main(String[] args) {

        //创建一个Buffer, 大小为 5, 即可以存放5个int
        IntBuffer intBuffer = IntBuffer.allocate(5);

        //向buffer 存放数据 存放了 0 2 4 6 8
        for(int i = 0; i < intBuffer.capacity(); i++) {
            intBuffer.put( i * 2);
        }

        //将buffer转换,读写切换(!!!)
        intBuffer.flip();//将buffer的读写状态切换 从写--->读
        intBuffer.position(1);//position函数能定位buffer的索引位置 设置为1则索引为1 对应的数字是2
        System.out.println(intBuffer.get());//输出2
        
        intBuffer.limit(3);
        while (intBuffer.hasRemaining()) {
            System.out.println(intBuffer.get());
        }
    }

通道(Channel)

NIO的通道类似于流,但有些区别如下:

  • 通道可以同时进行读写,而流只能读或者只能写
  • 通道可以实现异步读写数据
  • 通道可以从缓冲读数据,也可以写数据到缓冲
    在这里插入图片描述

Channel在NIO中是一个接口

public interface Channel extends AttributeMap, ChannelOutboundInvoker, Comparable<Channel>

常用的 Channel 类有:FileChannel、DatagramChannel、ServerSocketChannel 和 SocketChannel。【ServerSocketChanne 类似 ServerSocket , SocketChannel 类似 Socket】


channel读写文件实例
输出文件:

文件 <— 输出流 <— FileChannel <— ByteBuffer <— 程序的字符串

public static void main(String[] args) throws Exception{

        String str = "hello,world";
        //创建一个输出流->channel
        FileOutputStream fileOutputStream = new FileOutputStream("d:\\file01.txt");

        //通过 fileOutputStream 获取 对应的 FileChannel
        //这个 fileChannel 真实 类型是  FileChannelImpl
        FileChannel fileChannel = fileOutputStream.getChannel();

        //创建一个缓冲区 ByteBuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        //将 str 放入 byteBuffer
        byteBuffer.put(str.getBytes());


        //对byteBuffer 进行flip
        byteBuffer.flip();

        //将byteBuffer 数据写入到 fileChannel
        fileChannel.write(byteBuffer);
        fileOutputStream.close();

    }

首先创建输出流,然后通过输出流获得Channel对象,创建缓冲区,将要输出的数据放到缓冲区,再调用flip,最后将缓冲区数据写入Channel对象

读入文件:

文件 —> 输入流 —> FileChannel —> ByteBuffer —> 程序显示

 //创建文件的输入流
        File file = new File("d:\\file01.txt");
        FileInputStream fileInputStream = new FileInputStream(file);

        //通过fileInputStream 获取对应的FileChannel -> 实际类型  FileChannelImpl
        FileChannel fileChannel = fileInputStream.getChannel();

        //创建缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());

        //将 通道的数据读入到Buffer
        fileChannel.read(byteBuffer);

        //将byteBuffer 的 字节数据 转成String
        System.out.println(new String(byteBuffer.array()));
        fileInputStream.close();

选择器(Selector)
  • Java 的 NIO,用非阻塞的 IO 方式。可以用一个线程,处理多个的客户端连接,就会使用到Selector(选择器)
  • Selector 能够检测多个注册的通道上是否有事件发生(注意:多个Channel以事件的方式可以注册到同一个Selector),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。这样就可以只用一个单线程去管理多个通道,也就是管理多个连接和请求
  • 只有在 连接/通道 真正有读写事件发生时,才会进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程,避免了多线程之间的上下文切换导致的开销

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值