1000道Java面试题之Java IO 附答案

大家好,我是青空。

最近又赶上跳槽的高峰期,好多粉丝,都问我要有没有最新面试题,能不能做一些分享,和做一些面试题解析的系列文章。

青空收到消息之后,觉得这个建议挺不错的。那我就计划简单及概念性的面试题就多个面试题汇总成一片文章,比较复杂的面试题就单独拎出来讲讲。

文末领取面试大全

1.IO多路复用的底层原理

IO多路复用使用两个系统调用(select/poll/epoll和recvfrom),blocking IO只调用了 recvfrom; select/poll/epoll 核心是可以同时处理多个connection,而不是更快,所以连接数不高的话,性能不一 定比多线程+阻塞IO好,多路复用模型中,每一个socket,设置为nonblocking,阻塞是被select这个函数 block,而不是被socket阻塞的。

  1. select机制 客户端操作服务器时就会产生这三种文件描述符(简称fd):writefds(写)、readfds(读)、和 exceptfds(异 常)。select会阻塞住监视3类文件描述符,等有数据、可读、可写、出异常 或超 时、就会返回;返回后 通过遍历fdset整个数组来找到就绪的描述符fd,然后进行对应的IO操作。
  • 优点: 几乎在所有的平台上支持,跨平台支持性好

  • 缺点: 由于是采用轮询方式全盘扫描,会随着文件描述符FD数量增多而性能下降。每次调用 select(), 需要把 fd 集合从用户态拷⻉到内核态,并进行遍历(消息传递都是从内核到用户空间) 默认单个进程打开的FD有限制是1024个,可修改宏定义,但是效率仍然慢。

  1. poll机制基本原理与select一致,只是没有最大文件描述符限制,因为采用的是链表存储fd。

  2. epoll机制 epoll之所以高性能是得益于它的三个函数

  • epoll_create()系统启动时,在Linux内核里面申请一个B+树结构文件系统,返回 epoll对象,也是 一个fd

  • epoll_ctl() 每新建一个连接,都通过该函数操作epoll对象,在这个对象里面修改添加 删除对应的 链接fd, 绑定一个callback函数。

  • epoll_wait() 轮训所有的callback集合,并完成对应的IO操作

优点: 没fd这个限制,所支持的FD上限是操作系统的最大文件句柄数,1G内存大概支持10万个句柄 效率提高,使用回调通知而不是轮询的方式,不会随着FD数目的增加效率下降 内核和用户空间mmap同 一块内存实现

2.缓冲区是什么意思?

Buffer 是一个对象, 它包含一些要写入或者刚读出的数据。在 NIO 中加入 Buffer 对象,体现了 新库与原 I/O 的一个重要区别。在面向流的 I/O 中,您将数据直接写入或者将数据直接读到 Stream 对象中

在 NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入 数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,您都是将它放到缓冲区中。

缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一个 缓冲区不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程

3.通道是个什么意思?

通道是对原 I/O 包中的流的模拟。到任何目的地(或来自任何地方)的所有数据都必须通过一个 Channel 对象(通道)。一个 Buffer 实质上是一个容器对象。发送给一个通道的所有对象都必须 首先放到缓冲区中;同样地,从通道中读取的任何数据都要读到缓冲区中。

Channel是一个对象,可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就像是流。正如前面提到的,所有数据都通过 Buffer 对象来处理。您永远不会将字节直接写入通道中,相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道中读取字节, 而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。

4.同步、异步、阻塞、非堵塞

同/异、阻/非堵塞的组合,有四种类型,如下表:

组合方式性能分析
同步非阻塞提升 I/O 性能的常用手段,就是将 I/O 的阻塞改成非阻塞方式,尤其在网络 I/O 是⻓连接, 同时传输数据也不是很多的情况下,提升性能非常有效。这种方式通常能提升 I/O 性能,但 是会增加CPU 消耗,要考虑增加的 I/O 性能能不能补偿 CPU 的消耗,也就是系统的瓶颈是在 I/O 还是在 CPU 上。
异步阻塞这种方式在分布式数据库中经常用到,例如在往一个分布式数据库中写一条记录,通常会有 一份是同步阻塞的记录,而还有两至三份是备份记录会写到其它机器上,这些 备份记录通 常都是采用异步阻塞的方式写 I/O。异步阻塞对网络 I/O 能够提升效率,尤其像上面这种同 时写多份相同数据的情况。
异步非阻塞这种组合方式用起来比较复杂,只有在一些非常复杂的分布式情况下使用,像集群之 间的 消息同步机制一般用这种 I/O 组合方式。如 Cassandra 的 Gossip 通信机制就是采用异步非 阻塞的方式。它适合同时要传多份相同的数据到集群中不同的机器,同时 数据的传输量虽 然不大,但是却非常频繁。这种网络 I/O 用这个方式性能能达到最高。

5.阻塞与非阻塞

阻塞与非阻塞主要是从 CPU 的消耗上来说的,阻塞就是 CPU 停下来等待一个慢的操作完成 CPU 才接着 完成其它的事。非阻塞就是在这个慢的操作在执行时 CPU 去干其它别的事,等这 个慢的操作完成时, CPU 再接着完成后续的操作。虽然表面上看非阻塞的方式可以明显的提高 CPU 的利用率,但是也带了另外一种后果就是系统的线程切换增加。增加的 CPU 使用时间能不能补偿系统的切换成本需要好好评估。

6.同步与异步

同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。而异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。我们可以用打电话和发短信来很好的比喻同步与异步操作。

7.什么是AIO

AIO 是 Java 1.7 之后引入的包,是 NIO 的升级版本,提供了异步非堵塞的 IO 操作方式,所以 人们叫它 AIO(Asynchronous IO),异步 IO 是基于事件和回调机制实现的,也就是应用操 作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续 的操作

8.什么是NIO

是 Java 1.4 引入的 java.nio 包,提供了 Channel、Selector、Buffer 等新的抽象,可以构建多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层高性能的数据操作方

9.什么是BIO

BIO 就是传统的 java.io 包,它是基于流模型实现的,交互的方式是同步、阻塞方式,也就是 说在读入 输入流或者输出流时,在读写动作完成之前,线程会一直阻塞在那里,它们之间的调用时可靠的线性顺 序。它的优点就是代码比较简单、直观;缺点就是 IO 的效率和扩展性很低,容易成为应用性能瓶颈。

10.流一般需要不需要关闭,如果关闭的话在用什么方法,一 般要在那个代码块里面关闭比较好,处理流是怎么关闭 的,如果有多个流互相调用传入是怎么关闭的?

  1. 流一旦打开就必须关闭,使用close方法

  2. 放入finally语句块中(finally 语句一定会执行)

  3. 调用的处理流就关闭处理流

  4. 多个流互相调用只关闭最外层的流

11.什么是节点流,什么是处理流,它们各有什么用处,处理流 的创建有什么特征?

  1. 节点流 直接与数据源相连,用于输入或者输出

  2. 处理流:在节点流的基础上对之进行加工,进行一些功能的扩展

  3. 处理流的构造器必须要传入节点流的子类

12.PrintStream、BufferedWriter、PrintWriter的比 较?

  1. PrintStream类的输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成 PrintStream后进行输出。它还提供其他两项功能。与其他输出流不同, PrintStream 永远不会抛 出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,可以创建一个 PrintStream

  2. BufferedWriter:将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过write()方法可以将获取到的字符输出,然后通过newLine()进行换行操作。BufferedWriter中的字符流必须通过调用flush方法才能将其刷出去。并且 BufferedWriter只能对字符流进行操作。如果要对字节流操作,则使用 BufferedInputStream

  3. PrintWriter的println方法自动添加换行,不会抛异常,若关心异常,需要调用 checkError方法看是否有异常发生,PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush)

13.字节流和字符流的区别?

字节流读取的时候,读到一个字节就返回一个字节;字符流使用了字节流读到一个或多个字节 (中文对 应的字节数是两个,在 UTF-8 码表中是 3 个字节)时。先去查指定的编码表,将查到的字符返回。字节流可以处理所有类型数据,如:图片,MP3,AVI视频文件,而字符流只能处理字符数据。只要是处理纯文本数据,就要优先考虑使用字符流,除此之外都用字节流。字节流主要是操作 byte 类型数据, 以 byte 数组为准,主要操作类就是 OutputStream、 InputStream字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组。所以字符流是由 Java 虚拟机将字节转化为 2 个字节的 Unicode 字符为单位的字符而成的,所以它对多国语言支持性比较好! 如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点。在程序中一个字符等于两个字节,java 提供了 Reader、Writer 两个专⻔操作字符流的类。

14.如何实现 java 序列化?

序列化的实现,将需要被序列化的类实现Serializable 接口,该接口没有需要实现的方法, implements Serializable 只是为了标注该对象是可被序列化的,然后使用一个输出流(如: File Output Stream)来构造一个 Object Output Stream(对象流)对象,接着,使用 Object Output Stream 对象的 write Object(Object obj)方法就可以将参数为 obj 的对象写出(即保存其状态),要恢复的话则用输入流。

15.什么是 java序列化?

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流 化后的对 象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时 所引发的问题

16.Java 中有几种类型的流?

  1. 按照流的方向:输入流(inputStream)和输出流(outputStream);

  2. 按照实现 功能分:节点流(可以从或向一个特定的地方(节点)读写数据。如 FileReader)和处 理流 (是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如 BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其 他流的多 次包装,称为流的链接);

  3. 按照处理数据的单位: 字节流和字符流。字节流继 承于 InputStream 和 OutputStrea,字符流继 承于InputStreamReader 和 OutputStreamWriter 。

参考资料

《Java核心技术卷一》

面试大全包括:包括 Java 集合、JVM、多线程、并发编程、设计模式、SpringBoot、SpringCloud、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、Python、HTML、CSS、Vue、React、JavaScript、Android 大数据、阿里巴巴等大厂面试题等、等技术栈!

领取方式:扫描下方公众号【蚂蚁原图】回复【面试题】即可获取

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值