BIO、NIO、AIO、Netty面试题

什么是IO

Java中I/O是以流为基础进行数据的输入输出的,所有数据被串行化(所谓串行化就是数据要按顺序进行输入输出)写入输出流。简单来说就是java通过io流方式和外部设备进行交互。

在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据传输流,字符串流,对象流等等等。

比如程序从服务器上下载图片,就是通过流的方式从网络上以流的方式到程序中,再到硬盘中。

同步与异步,阻塞与非阻塞的区别

  • 同步,一个任务的完成之前不能做其他操作,必须等待(等于在打电话)
  • 异步,一个任务的完成之前,可以进行其他操作(等于在聊QQ)
  • 阻塞,是相对于CPU来说的, 挂起当前线程,不能做其他操作只能等待
  • 非阻塞,,无须挂起当前线程,可以去执行其他操作

什么是BIO

同步并阻塞,服务器实现一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,没处理完之前此线程不能做其他操作,当然可以通过线程池机制改善。BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。

什么是NIO

同步非阻塞,服务器实现一个连接一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4之后开始支持。

什么是AIO

异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由操作系统先完成了再通知服务器应用去启动线程进行处理,AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用操作系统参与并发操作,编程比较复杂,JDK1.7之后开始支持。

AIO属于NIO包中的类实现,其实IO主要分为BIO和NIO,AIO只是附加品,解决IO不能异步的实现。

在以前很少有Linux系统支持AIO,Windows的IOCP就是该AIO模型。但是现在的服务器一般都是支持AIO操作。

什么Netty

Netty是由JBOSS提供的一个Java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。

BIO和NIO、AIO的区别

  • BIO是阻塞的,NIO是非阻塞的;
  • BIO是面向流的,只能单向读写,NIO是面向缓冲的, 可以双向读写;
  • 使用BIO做Socket连接时,由于单向读写,当没有数据时,会挂起当前线程,阻塞等待,为防止影响其它连接,,需要为每个连接新建线程处理.,然而系统资源是有限的,,不能过多的新建线程,线程过多带来线程上下文的切换,从来带来更大的性能损耗,因此需要使用NIO进行BIO多路复用,使用一个线程来监听所有Socket连接,使用本线程或者其他线程处理连接
  • AIO是非阻塞,以异步方式发起 I/O 操作。当 I/O 操作进行时可以去做其他操作,由操作系统内核空间提醒IO操作已完成。

什么是内核空间

我们的应用程序是不能直接访问硬盘的,我们程序没有权限直接访问,但是操作系统(Windows、Linux......)会给我们一部分权限较高的内存空间,它叫内核空间,和我们的实际硬盘空间是有区别的。

在这里插入图片描述

五种IO模型

注意:这里的用户空间就是应用程序空间

阻塞BIO(blocking I/O)

在内核将数据准备好之前,系统调用会一直等待所有的套接字,默认的是阻塞方式。

非阻塞NIO(noblocking I/O)

在这里插入图片描述

异步AIO(asynchronous I/O)

在这里插入图片描述

当应用程序请求数据时,内核一方面去取数据报内容返回,另一方面将程序控制权还给应用进程,应用进程继续处理其他事情,是一种非阻塞的状态。

信号驱动IO(signal blocking I/O)

在这里插入图片描述

信号驱动IO模型,应用进程告诉内核:当数据报准备好的时候,给我发送一个信号,对SIGIO信号进行捕捉,并且调用我的信号处理函数来获取数据报。

IO多路复用(I/O multiplexing)

在这里插入图片描述

IO多路复用是多了一个select函数,select函数有一个参数是文件描述符集合,对这些文件描述符进行循环监听,当某个文件描述符就绪时,就对这个文件描述符进行处理。

IO多路转接是属于阻塞IO,但可以对多个文件描述符进行阻塞监听,所以效率较阻塞IO的高。

什么是比特(Bit),什么是字节(Byte),什么是字符(Char),它们长度是多少,各有什么区别

  • Bit最小的二进制单位 ,是计算机的操作部分,取值0或者1
  • Byte是计算机中存储数据的单元,是一个8位的二进制数,(计算机内部,一个字节可表示一个英文字母,两个字节可表示一个汉字。) 取值(-128-127)
  • Char是用户的可读写的最小单位,它只是抽象意义上的一个符号。在java里面由16位bit组成Char 取值(0-65535)
  • Bit 是最小单位,计算机它只能认识0或者1
  • Byte是8个字节,是给计算机看的

什么叫对象序列化,什么是反序列化,实现对象序列化需要做哪些工作

  • 对象序列化,将对象以二进制的形式保存在硬盘上
  • 反序列化;将二进制的文件转化为对象读取
  • 实现serializable接口,不想让字段放在硬盘上就加transient

在实现序列化接口是时候一般要生成一个serialVersionUID字段,它叫做什么,一般有什么用

如果用户没有自己声明一个serialVersionUID,接口会默认生成一个serialVersionUID;

强烈建议用户自定义一个serialVersionUID,因为默认的serialVersinUID对于class的细节非常敏感,反序列化时可能会导致InvalidClassException这个异常;

比如说先进行序列化,然后在反序列化之前修改了类,那么就会报错。因为修改了类,对应的SerialversionUID也变化了,而序列化和反序列化就是通过对比其SerialversionUID来进行的,一旦SerialversionUID不匹配,反序列化就无法成功。

BufferedReader属于哪种流,它主要是用来做什么的,它里面有那些经典的方法

属于处理流中的缓冲流,可以将读取的内容存在内存里面,有readLine()方法。

Java中流类的超类主要有那些?

超类代表顶端的父类(都是抽象类)

  • java.io.InputStream
  • java.io.OutputStream
  • java.io.Reader
  • java.io.Writer

IO的常用类

在这里插入图片描述

网络操作IO编程演变历史

BIO编程会出现什么问题?

BIO是阻塞的,读取写出操作都是非常浪费资源的。

在这里插入图片描述

多线程解决BIO编程会出现的问题

使用多线程是可以解决堵塞等待时间很长的问题,因为它可以充分发挥CPU,然而系统资源是有限的,不能过多的新建线程,线程过多带来线程上下文的切换,从来带来更大的性能损耗。

万一请求越来越多,线程越来越多那我CPU不就炸了?

在这里插入图片描述

线程池解决多线程BIO编程会出现的问题

使用线程池。线程池固然可以解决这个问题,万一需求量还不够还要扩大线程池。但是这是我们自己靠着自己的思想完成的IO操作,Socket 上来了就去创建线程去抢夺CPU资源,线程都做IO去了。

在这里插入图片描述

使用NIO实现网络通信

NIO是JDK1.4提供的操作,它的流还是流,没有改变,服务器实现的还是一个连接一个线程,但是:客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4之后开始支持。

在这里插入图片描述

什么是通道(Channel)

Channel是一个对象,可以通过它读取和写入数据。 通常我们都是将数据写入包含一个或者多个字节的缓冲区,然后再将缓存区的数据写入到通道中,将数据从通道读入缓冲区,再从缓冲区获取数据。

Channel 类似于原I/O中的流(Stream),但有所区别:

  • 流是单向的,通道是双向的,可读可写。
  • 流读写是阻塞的,通道可以异步读写。

什么是选择器(Selector)

Selector可以称它为通道的集合,每次客户端来了之后我们会把Channel注册到Selector中并且我们给它一个状态,再用死循环来判断(判断是否做完某个操作,完成某个操作后改成不一样的状态)状态是否发生变化,直到IO操作完成后再退出死循环。

什么是Buffer(缓冲区)

Buffer 是一个缓冲数据的对象, 它包含一些要写入或者刚读出的数据。

在普通的面向流的 I/O 中,一般将数据直接写入或直接读到 Stream 对象中。但是有了Buffer(缓冲区)后,数据第一步到达的是Buffer(缓冲区)中。缓冲区实质上是一个数组(底层完全是数组实现的)。通常它是一个字节数组,内部维护几个状态变量,可以实现在同一块缓冲区上反复读写(不用清空数据再写)。

使用Netty实现网络通信

Netty是由JBOSS提供的一个Java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的Socket服务开发。

Netty的原理就是NIO,它是基于NIO的一个完美的封装,并且优化了NIO,使用他非常方便,简单快捷。

 

参考:

posted @ 2021-12-25 08:29  残城碎梦  阅读(134)  评论(0编辑  收藏  举报