【2023】NIO vs BIO对比及 IO模型

1、stream vs channel

通道(Channel):由 java.nio.channels 包定义 的。Channel 表示 IO 源与目标打开的连接。Channel 类似于传统的“流”。只不过 Channel 本身不能直接访问数据,Channel 只能与 Buffer 进行交互。(Channel本身不存储数据,因此需要配合缓冲区进行传输)

Channel 如何做到异步?
例如下图,我们应NIO的 Selector来监听 多个Channel,由于Channel是既可以读也可以写的,因此Selector监听Channel时,并不需要像BIO一样,阻塞到Channel有数据才返回,则是可以达到 当Channel有数据时,主动去通知Selector,让Selector去处理,这样的话,Selector就不需要阻塞了,这就是Channel的异步。

在这里插入图片描述

最明显的区别:一个是阻塞读取,一个是到达读取

  • stream 是BIO,也就是阻塞模式,分IN OUT两个,无论是IN还是OUT,在进行消息处理是是阻塞当前线程的,也就是需要等待对方的数据到达。

  • channel 是NIO,可以看作其包含了INOUT是一个通道的概念,channel的实现有很多,针对本地文件的,针对网络的,针对内存的,不同的其表现并不完全相同,但可以理解为:channel的数据消费是将数据写入缓冲区buffer,或从buffer读取数据;这个过程是可以通过selector来辅助监听channel的状态

  • stream不会自动缓冲数据,channel会利用系统提供的发送缓冲区,接收缓冲区(更为底层)

  • stream仅支持阻塞 API,channel同时支持阻塞,非阻塞API,网络channel可配合selector实现多路复用

  • 二者均为全双工,即读写可以同时进行

2、IO模型

同步阻塞、非同步阻塞、多路复用 (都属于同步IO) : 异步阻塞(没有此情况)、异步非阻塞 (异步IO)

  • 同步:线程自己去获取结果(一个线程)
  • 异步:线程自己不去获取结果,而是由其他线程获取结果(至少两个线程)。
    • 异步只有非阻塞
      在这里插入图片描述

网络io模型

  • 阻塞IO :用户线程在读取期间被阻塞掉了,在读取期间不能执行其他的东西。

    在这里插入图片描述

  • 非阻塞IO:用户线程一直循环去访问内核空间,是否有数据,如果没有不会阻塞,会直接返回用户空间;直到读取到数据;进行复制数据,复制数据期间也还是会阻塞,直到复制完成返回。

    在这里插入图片描述

  • 多路复用:不会直接去调用read方法,会先去调用select,阻塞住,直到发送read事件,才会去内核空间读取复制数据到用户线程回来

    • 阻塞io情况:线程执行完read事件后来了一个accept事件,他会去建立连接,中间是 不能继续去接收第一个channel的read事件的,需要等channel2连接建立之后才会去执行read事件

      在这里插入图片描述

    • 多路复用情况:select方法执行只会,就会去等待事件的发生,当事件来的时候,就会立即触发select,把事件全部注册到select中;如果多个事件一起发生,则会一起把事件注册回来,然后再去把事件执行掉,不会再等待c2,完成才会去执行把c3注册事件。

    在这里插入图片描述

  • 信号驱动

  • 异步IO:

    • 异步读取文件

    • 使用AsynchronousFileChannel类实现

      • 多线程情况下,当主线程执行完了的时候,即使守护线程仍然还在执行,也会结束

      守护线程

      指为其他线程服务的线程。在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出。而如果有非守护线程未执行完时,则JVM不会关闭

    public static void main(String[] args) throws IOException {
            try (AsynchronousFileChannel channel =  AsynchronousFileChannel.open(Paths.get("words2.txt"), StandardOpenOption.READ)){
                /*参数1 ByteBuffer
                * 参数2 读取的起始位置
                * 参数3 附件
                * 参数4 回调对象 CompletionHandler
                * */
                ByteBuffer buffer = ByteBuffer.allocate(16);
                log.debug("read begin...");
                channel.read(buffer, 0,buffer, new CompletionHandler<Integer ,ByteBuffer>() {
    
                    @Override //read 成功  (实际字节数,传入的buffer)
                    public void completed(Integer result, ByteBuffer attachment) {
                        log.debug("read...{}",result);
                        attachment.flip();
                        String a = StandardCharsets.UTF_8.decode(attachment).toString();
                        log.debug("read...{}",a);
    
                    }
                    @Override //read 失败
                    public void failed(Throwable exc, ByteBuffer attachment) {
                        exc.printStackTrace();
                    }
                });
                log.debug("read end...");
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.in.read();
        }
    

参考:uxil网络编程

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值