阻塞IO和非阻塞IO的区别 (BIO&NIO)

释义:

BIO:是指blocking IO
NIO:是指noblocking IO(非阻塞io),也可以理解为newio(新io)

理解新io和老io:

司机去问每一个顾客从哪下车(多次阻塞得起线程) 司机去问售票员从哪停车(还是得阻塞,但是不用额外起线程,也不一直等待,去干别的事)
BIO当客户端连接服务器端时起的线程太多,学了NIO以后可以用一个线程来处理多个请求

两者的区别:

1、数据阻塞和非阻塞的区别
2、数据传输的方式:Bio通过流的方式进行传输 ,NIo是通过包(数据块)的方式进行数据传输
3、BIO读写分离 ,NIO即可读也可以写

在了解BIO与NIO之前我们先要了解一个概念:什么是流?

流的概念、作用:

概念:流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象,即数据在两设备间的传输称为流
作用:流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

BIO

分类:

  1. 根据处理数据类型的不同分为:字符流和字节流
  2. 根据数据流向不同分为:输入流和输出流
  3. 按照流是否直接与特定的地方(如磁盘、内存、设备等)相连(是否可以直接作用于文件),分为节点流和处理流两类。

字符流和字节流:
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。 字节流和字符流的区别:
1.读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
2. 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
字节流:一次读入或读出是8位二进制。
字符流:一次读入或读出是一个或者多个字节。
设备上的数据无论是图片或者视频,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。
结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。

输入流和输出流:
输入流只能进行读操作,输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。
结论:输入流:InputStream或者Reader:从文件中读到程序中;
输出流:OutputStream或者Writer:从程序中输出到文件中;

节点流和处理流
节点流:直接与数据源相连,读入或读出。直接使用节点流,读写不方便,为了更快的读写文件,才有了处理流。如FileInputStream(“D:/abc.txt”)在读取文件内容的时候,我们直接传入文件的路径。
处理流:在节点流的基础上,再套接一层,套接在节点流上的就是处理流。如new BufferedInputStream(new FileInputStream(file))处理流的构造方法总是要带一个其他的流对象做参数。
结论:直接作用于数据源(文件名)的流是节点流,不直接作用于数据源(文件名)的流是处理流

NIO

Java NIO 由以下几个核心部分组成:

  • Channels
  • Buffers
  • Selectors

Channel :通道,有点像流。但又有些不同:
既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
通道可以异步地读写。
通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。(buffer.flip():反转Buffer,既可以用来读也可以用来写)

Buffer:缓冲区,数据是从通道读入缓冲区,从缓冲区写入到通道中的。
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
通过flip()方法将Buffer从写模式切换到读模式。在读模式下,可以读取之前写入到buffer的所有数据。一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入

Selector:允许单线程处理多个 Channel。
事实上,可以只用一个线程处理所有的通道。对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些资源(如内存)。因此,使用的线程越少越好。但是,需要记住,现代的操作系统和CPU在多任务方面表现的越来越好,所以多线程的开销随着时间的推移,变得越来越小了。实际上,如果一个CPU有多个内核,不使用多任务可能是在浪费CPU能力。
为了将Channel和Selector配合使用,必须将channel注册到selector上。通过SelectableChannel.register()方法来实现.
与Selector一起使用时,Channel必须处于非阻塞模式下。这意味着不能将FileChannel与Selector一起使用,因为FileChannel不能切换到非阻塞模式。而套接字通道都可以。

注意register()方法的第二个参数。这是一个“interest集合”,意思是在通过Selector监听Channel时对什么事件感兴趣。可以监听四种不同类型的事件:
Connect
Accept
Read
Write
通道触发了一个事件意思是该事件已经就绪。所以,某个channel成功连接到另一个服务器称为“连接就绪”。一个server socket channel准备好接收新进入的连接称为“接收就绪”。一个有数据可读的通道可以说是“读就绪”。等待写数据的通道可以说是“写就绪”。
这四种事件用SelectionKey的四个常量来表示:
SelectionKey.OP_CONNECT
SelectionKey.OP_ACCEPT
SelectionKey.OP_READ
SelectionKey.OP_WRITE

如果你对不止一种事件感兴趣,那么可以用“位或”操作符将常量连接起来,如下:
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值