1.什么是流?作用是什么?
答:流是一种有顺序的,有起点和终点的字节集合,是对数据传输的总成或抽象。
即数据在两设备之间的传输称之为流,流的本质是数据传输,根据数据传输的特性讲流抽象为各种类,方便更直观的进行数据操作。
2.IO流的分类?
答:根据数据处理类的不同分为:字符流和字节流;
根据数据流向不同分为:输入流和输出流。
3.字符流和字节流的区别是区别是什么?
答:字符流的由来:因为数据编码的不同,而有了对字符进行高效操作的流对象,其本质就是基于字节流读取时,去查了指定的码表。
字符流和字节流的区别:
(1)读写单位不同:字节流一字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
(2)处理对象不同:字节流能处理所有类型的数据(例如图片,avi),而字符流只能处理字符类型的数据。
(3)字节流操作的时候本身是不会用到缓冲区的,是对文件本身的直接操作。而字符流在操作的时候是会用到缓冲区的,通过缓冲区来操作文件。
结论:优先使用字节流,首先因为在硬盘上所有的文件都是以字节的形式进行传输或保存的,包括图片等内容。但是字符流只是在内存中才会形成,所以在开发中字节流使用广泛。
4.什么是java序列化,如何实现java序列化?
答:Java对象的序列化指将一个java对象写入OI流中,与此对应的是,对象的反序列化则从IO流中恢复该java对象。
如果要让某个对象支持序列化机制,则必须让它的类是可序列化的,为了让某个类是可序列化的,该类必须实现Serializable接口或Externalizable接口
5.读写原始数据,采用什么流?
答:InputStream/OutputStream
6.为了提高读写性能,采用什么流?
答:BufferedInputStream/BufferedOutputStream
7.对各种基本数据类型和String类型的读写,采用什么流?
答:DataInputStream/DataOutputStream
8.指定字符编码,采用什么流?
答:InputStreamReader/OutputStreamWriter
9.Linux常见IO模型有哪些?
答:**linux下有五种常见的IO模型:
①阻塞 I/O(blocking IO)
②非阻塞 I/O(nonblocking IO)
③I/O 多路复用( IO multiplexing)
④信号驱动 I/O( signal driven IO)
⑤异步 I/O(asynchronous IO)
只有5是异步模型,其余皆为同步模型
10.什么是阻塞IO模型?
答:阻塞IO模型是最常见的IO模型了,对于所有的“慢速设备”(socket、pipe、fifo、terminal)的IO默认的方式都是阻塞的方式。阻塞就是进程放弃cpu,让给其他进程使用cpu。
进程阻塞最显著的表现就是进程睡眠了。阻塞的时间通常取决于数据是否到来。 这种方式使用简单,但随之而来的问题就是会形成阻塞,需要独立线程配合,而这些线程在大多数时候都是没有进行运算的。
Java的BIO使用这种方式,问题带来的问题很明显,一个Socket需要一个独立的线程,因此,会造成线程膨胀。
11.什么是非阻塞IO模型?
答:非阻塞IO就是设置IO相关的系统调用为non-blocking,随后进行的IO操作无论有没有可用数据都会立即返回,并设置errno为EWOULDBLOCK或者EAGAIN。
我们可以通过主动check的方式(polling,轮询)确保IO有效时,随之进行相关的IO操作。当然这种方式看起来就似乎不太靠谱,浪费了太多的CPU时间,用宝贵的CPU时间做轮询太不靠谱儿了。
12.什么是多路复用IO模型?
答:为了解决阻塞I/O的问题,就有了I/O多路复用模型,多路复用就是用单独的线程(是内核级的, 可以认为是高效的优化的) 来统一等待所有的socket上的数据, 一当某个socket上有数据后, 就启用用户线程(可能是从线程池中取出, 而不是重新生成), copy socket data, 并且处理message.因为网络延迟的原因, 同时在处理socket data的用户线程往往比实际的socket数量要少很多. 所以实际应用中, 大部分是用线程池, 池中thread数量可随socket的高峰和低谷 而动态调整.
多路复用I/O中内核中统一的wait socket data那部分可以理解成是非阻塞, 也可以理解成阻塞. 可以理解成非阻塞 是因为它不是等到socket数据全部到达再处理, 而是有了一部分数据就会调用用户线程来处理, 理解成阻塞, 是因为它和用户空间(Appliction)层的非阻塞socket的不同是: socket中没有数据时, 内核还是wait(阻塞)的, 而用户空间的非阻塞socket没有数据也会返回, 会造成CPU的浪费.
Linux下的select和poll 就是多路复用模式,poll相对select,没有了句柄数的限制,但他们都是在内核层通过轮询socket句柄的方式来实现的, 没有利用更底层的notify机制. 但就算是这样,相对阻塞socket也已经进步了很多很多了! 毕竟用一个内核线程就解决了,阻塞socket中N多线程都在无谓地wait的局面.
多路复用I/O 还是让用户层来copy socket data. 这个过程是将内核中的socket buffer copy到用户空间的 buffer. 这有两个问题: 一是多了一次内核空间switch到用户空间的过程, 二是用户空间层不便暴露很低层但很高效的copy方式(比如DMA), 所以如果由内核层来做这个动作, 可以更好地提高效率!
13.什么是信号驱动IO模型?
答:所谓信号驱动,就是利用信号机制,安装信号SIGIO的处理函数(进行IO相关操作),通过监控文件描述符,当其就绪时,通知目标进程进行IO操作(signal handler)。
14.什么是异步IO模型?
答:由于异步IO请求只是写入了缓存,从缓存到硬盘是否成功不可知,因此异步IO相当于把一个IO拆成了两部分,一是发起请求,二是获取处理结果。
因此,对应用来说增加了复杂性。但是异步IO的性能是所有很好的,而且异步的思想贯穿了IT系统方方面面。
15.select、poll、epoll的区别是什么?
答:①支持一个进程所能打开的最大连接数
select 是 32位机默认是1024个,64位机默认是2048。
poll 本质上于select没有区别,但是它没有最大连接数的限制,原因是它是基于链表来存储的。
epoll 虽然有连接数上限,但是很大,1G内存的机器上可以打开10万左右的连接,2G内存的可以打开20万左右的连接。
②fd剧增后带来的I/O效率问题
select 每次调用事都会对连接进行线性遍历,所以随着fd的增加会造成遍历速度慢,呈线性下降性能问题。
poll 同上
epoll epoll内核中实现是根据每个fd的callback函数来实现的,只有活跃的socket才会主动调用callback,所以在活跃的socket较少的情况下,使用epoll没有前面两者的线性下降的性能问题,但是所有的socket都很活跃的情况下,可能会有性能问题。
③消息传递方式
select 内核需要将消息传递到用户空间,都需要内核拷贝动作
poll 同上
epoll 通过内核和用户空间共享一块内存来实现的。
16.Java 中 BIO 、NIO 、AIO 的区别是什么?
答:①含义不同:
BIO(Blocking IO)是同步并阻塞的 IO,线程发起 IO 请求后,不论内核是否准备好 IO 操作,都会一直阻塞直到操作完成。
NIO(Non-blocking IO)是同步非阻塞的 IO,线程发起 IO 请求后立即返回;内核在做好 IO 操作的准备之后,通过调用注册的回调函数通知线程做 IO 操作,线程开始阻塞,直到操作完成。
AIO(Asynchronous IO)是异步非阻塞的 IO,线程发起 IO 请求,立即返回;内存做好 IO 操作的准备之后,做 IO 操作,直到操作完成或者失败,通过调用注册的回调函数通知线程做 IO 操作完成或者失败。
②应用场景不同:
BIO 从 JDK1.4 之前的版本,适用于低负载、低并发、业务逻辑耗时较长的场景;
NIO 从 JDK1.4 开始支持,适用于高负载高并发且业务逻辑简单(轻操作)的场景,典型场景是聊天服务器;
AIO 从 JDK1.7 开始支持,适用于高负载高并发且业务逻辑复杂(重操作)的场景,典型场景是相册服务器;
17.同步与异步、阻塞与非阻塞的区别是什么?
答:
同步与异步:
同步:调用线程发出同步请求后,在没有得到结果前,该调用就不会返回。前面的同步调用处理完了后才能处理下一个同步调用
异步:调用线程发出异步请求后,在没有得到结果前,该调用就返回了。真正的结果数据会在业务处理完成后以信号或者回调的形式通知调用者
阻塞与非阻塞:
阻塞:调用线程发出请求后,在没有得到结果前,该线程就会被挂起,此时该线程处于非可执行状态。直到返回结果返回后,此线程才会被唤醒,继续运行。
非阻塞:调用线程发出请求后,在没有得到结果前,该调用就返回了,整个过程该线程不会被挂起
例如:
同步阻塞: 张三把水壶放到火上,在旁边等水开;
同步非阻塞:张三把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有;
异步阻塞:张三把响水壶放到火上,在旁边等水开。
异步非阻塞:张三把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。
18.字节流、字符流的区别及适用场景分别是什么?
答:
区别:处理单元不同,J 字节流处理的最基本单位为 1 个字节,字符流处理的最基本的单元是 Unicode 代码单元(大小 2 字节);
字节流默认不使用缓冲区;字符流使用缓冲区。
适用场景:字节流实际上可以处理任何文件,因为字节是存储的基础单元;而待处理的流如果是可打印的字符,那么用字符流更方便一些。
JDK 中, 字节流操作一般都是 InputStream, OutputStream 以及各种包装类;而字符流字符操作一般使用 Writer,Reader 等