常见面试题和答案汇总(6):Java IO

目录

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

2. 缓冲区是什么意思?

3. 通道是个什么意思?

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

5. 什么是AIO,NIO,BIO

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

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

8. PrintStream、BufferedWriter、PrintWriter的比较?

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

10. 如何实现 java 序列化?

11. 什么是 java序列化?

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


【写在前面】

此文题目和答案都非原创。

是搜集了网络上分享的关于Java面试常见问题汇总,然后又逐个搜寻了答案,整理于此。

供自学,感谢相关题目和答案的原创分享者。

【相关链接】

常见面试题和答案汇总(1):Spring

常见面试题和答案汇总(2):SpringBoot

​​​​​​常见面试题和答案汇总(3):SpringCloud

常见面试题和答案汇总(4):Java基础

常见面试题和答案汇总(5):Java虚拟机

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

参考此文:Java IO多路复用机制详解

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

2. 缓冲区是什么意思?

参考文章:java缓冲区

缓冲区就是内存里的一块区域,把数据先存内存里,然后一次性写入,类似数据库的批量操作,这样效率比较高。

调用I\O操作时,实际上还是一个一个的读或者写,关键就在,CPU只有一个,不论是几个核心。CPU在系统调用时,会不会还要参与主要操作?参与多次就会花更多的时间。

系统调用时,若不用缓冲,CPU会酌情考虑使用中断。此时CPU是主动地,每个周期中都要花去一部分去询问I\O设备是否读完数据,这段时间CPU不能做任何其他的事情(至少负责执行这段模块的核不能)。所以,调用一次读了一个字,通报一次,CPU腾出时间处理一次。

而设置缓冲,CPU通常会使用 DMA 方式去执行 I\O 操作。CPU 将这个工作交给DMA控制器来做,自己腾出时间做其他的事,当DMA完成工作时,DMA会主动告诉CPU“操作完成”。这时,CPU接管后续工作。在此,CPU 是被动的。DMA是专门 做 I\O 与 内存 数据交换的,不仅自身效率高,也节约了CPU时间,CPU在DMA开始和结束时做了一些设置罢了。
所以,调用一次,不必通报CPU,等缓冲区满了,DMA 会对C PU 说 “嘿,伙计!快过来看看,把他们都搬走吧”。

综上,设置缓冲,就建立了数据块,使得DMA执行更方便,CPU也有空闲,而不是呆呆地候着I\O数据读来。从微观角度来说,设置缓冲效率要高很多。尽管,不能从这个程序上看出来。 几万字的读写\就能看到差距。


3. 通道是个什么意思?

参考文章:java 什么是通道_详解java NIO之Channel(通道)

通道(Channel)是java.nio的第二个主要创新。它们既不是一个扩展也不是一项增强,而是全新、极好的Java I/O示例,提供与I/O服务的直接连接。Channel用于在字节缓冲区和位于通道另一侧的实体(通常是一个文件或套接字)之间有效地传输数据。


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

参考文章:Java IO多路复用机制详解 (包含同步,异步,阻塞,非阻塞概念)

(1)同步和异步:描述的是用户线程与内核的交互方式

同步是指用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行;

异步是指用户线程发起IO请求后仍继续执行,当内核IO操作完成后会通知用户线程,或者调用用户线程注册的回调函数。

(2)阻塞和非阻塞:描述的是用户线程调用内核IO操作的方式

阻塞是指IO操作需要彻底完成后才返回到用户空间;

非阻塞是指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成。


5. 什么是AIO,NIO,BIO

参考文章:JAVA BIO与NIO、AIO的区别

IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。

(1)BIO:同步阻塞

     在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程响应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端线程会等待请求结束后才继续执行。

(2)NIO:同步非阻塞

    NIO本身是基于事件驱动思想来完成的,其主要想解决的是BIO的大并发问题: 在使用同步I/O的网络应用中,如果要同时处理多个客户端请求,或是在客户端要同时和多个服务器进行通讯,就必须使用多线程来处理。即,将每一个客户端请求分配给一个线程来单独处理。这样做虽然可以达到我们的要求,但同时又会带来另外一个问题。由于每创建一个线程,就要为这个线程分配一定的内存空间(也叫工作存储器),而且操作系统本身对线程的总数也有一定的限制。如果客户端的请求过多,服务端程序可能会因为不堪重负而拒绝客户端的请求,甚至服务器可能会因此而瘫痪。

    NIO基于Reactor,当socket有流可读或可写入socket时,操作系统会相应的通知应用程序进行处理,应用再将流读取到缓冲区或写入操作系统。即,这时已经不是一个连接就要对应一个处理线程了,而是有效的请求对应一个线程,当连接没有数据时,是没有工作线程来处理的。

   BIO与NIO一个比较重要的不同是,使用BIO时往往会引入多线程,每个连接一个单独的线程;而NIO则是使用单线程或者只使用少量的多线程,多个连接共用一个线程。

(3)AIO:异步非阻塞

    与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。  即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。  在JDK1.7中,这部分内容被称作NIO.2。


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

参考文章:关于Java IO流的知识点

(1)流一旦打开就必须关闭,使用close方法。​

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

(3)​调用的处理流就关闭处理流。

(4)​多个流互相调用只关闭最外层的流。


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

参考文章:IO流面试题

(1)节点流:直接与数据源相连,用于输入或者输出
(2)处理流:在节点流的基础上对之进行加工,进行一些功能的扩展
(3)处理流的构造器必须要 传入节点流的子类


8. PrintStream、BufferedWriter、PrintWriter的比较?

参考文章:PrintStream、BufferedWriter、PrintWriter的比较

(1)PrintStream

输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成PrintStream后进行输

出。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;而

是,异常情况仅设置可通过 checkError方法测试的内部标志。另外,为了自动刷新,可以创建一个

PrintStream

(2)BufferedWriter

将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过write()

方法可以将获取到的字符输出,然后通过newLine()进行换行操作。BufferedWriter中的字符流必须

通过调用flush方法才能将其刷出去。并且BufferedWriter只能对字符流进行操作。如果要对字节流

操作,则使用BufferedInputStream。

(3)PrintWriter

PrintWriter的println方法自动添加换行,不会抛异常,若关心异常,需要调用checkError方法看是

否有异常发生,PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush)。


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

参考文章:理解Java中字符流与字节流的区别

(1)字节流操作的基本单元为字节;字符流操作的基本单元为Unicode码元。

(2)字节流默认不使用缓冲区;字符流使用缓冲区。

(3)字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元。


10. 如何实现 java 序列化?

 参考文章:什么是Java序列化,如何实现java序列化

序列化的实现:类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。


11. 什么是 java序列化?

参考文章:什么是 java 序列化?什么情况下需要序列化?

(1)序列化:将 Java 对象转换成字节流的过程。

(2)反序列化:将字节流转换成 Java 对象的过程。

(3)当Java对象需要在网络上传输或持久化存储到文件中时,就需要对Java对象进行序列化处理。

(4)注意:某个类可以被序列化,则其子类也可以被序列化。
声明为 static 和 transient 的成员变量,不能被序列化。static 成员变量是描述类级别的属性,transient 表示临时数据。
反序列化读取序列化对象的顺序要保持一致。


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

(1)根据处理的数据类型分:字节流和字符流

(2)根据流向分:输入流和输出流

 

猜你喜欢

转载自blog.csdn.net/sulia1234567890/article/details/121749690