I/O流相关记录

I/O 多路复用实现方式有哪些,以及对应的区别
select ,poll , epoll 
select:它仅仅知道了,有 I/O 事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。所以 select 具有 O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长。 

poll:poll 本质上和 select 没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd 对应的设备状态, 但是它没有最大连接数的限制,原因是它是基于链表来存储的.

epoll:epoll 可以理解为 event poll,不同于忙轮询和无差别轮询,epoll 会把哪个流发生了怎样的 I/O 事件通知我们。所以我们说 epoll 实际上是事件驱动(每个事件关联上 fd)的,此时我们对这些流的操作都是有意义的。(复杂度降低到了 O(1)),通过红黑树和双链表数据结构,并结合回调机制,造就了 epoll 的高效,epoll_create(),epoll_ctl()和epoll_wait()系统调用。

传统 I/O 跟 NIO 的区别?

 所有 I/O 都被视为单个的字节的移动,通过一个称为 Stream 的对象一次移动一个字节。流 I/O 用于与外部世界接触。它也在内部使用,用于将对象转换为字节,然后再转换回对象。传统流 IO 的好处是使用简单,将底层的机制都抽象成流,但缺点就是性能不足。而且 IO 的各种流是阻塞的。这意味着,当一个线程调用 read() 或 write()时,该线程被阻 塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。原来的 I/O 库(在 java.io.*中) 与 NIO 最重要的区别是数据打包和传输的方式。 原来的I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。NIO 性能的优势就来源于缓冲的机制(buffer 机制),不管是读或者写都需要以块的形式写入到缓冲区中。NIO 实际上让我们对 IO 的操作更接近于操作系统的实际过程。NIO 作为非阻塞式的 IO,它的优点就在于,1、它由一个专门的线程去处理所有的 IO事件,并负责分发;2、事件驱动,只有事件到了才会触发,而不是同步的监听这个事件;3、线程之间通过 wait,notify 等方式通讯。保证每次上下文切换都是有意义的。减少无谓的线程切换。 当我们在执行持续性的操作(如上传下载)时,IO 的方式是要优于 NIO 的。分清情况,

面向流与面向缓冲

Java IO 和 NIO 之间第一个最大的区别是,IO 是面向流的,NIO 是面向缓冲区的。 Java IO 面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要 先将它缓存到一个缓冲区。 Java NIO 的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,

不要覆盖缓冲区里尚未处理的数据。

阻塞与非阻塞 IO

Java IO 的各种流是阻塞的。这意味着,当一个线程调用 read() 或 write()时,该线程被 阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。Java NIO 的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用 的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入 一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。线程通常将非阻塞 IO 的空闲时间用于在其它通道上执行 IO 操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。

选择器(Selectors)

Java NIO 的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用 一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入, 或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

NIO 提供了与标准 IO 不同的 IO 工作方式:

Channels and Buffers(通道和缓冲区):标准的 IO 基于字节流和字符流进行操作的,而 NIO 是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Asynchronous IO(异步 IO):Java NIO 可以让你异步的使用 IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。

Selectors(选择器):Java NIO 引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。​​​​​​​

合理选用。NIO 相对于 IO 流的优势:非阻塞 buffer 机制流替代块

I/O 流的分类

按照读写的单位大小来分:

l字符流:以字符为单位,每次次读入或读出是 16 位数据。其只能读取字符类型数据。(Java 代码接收数据为一般为 char 数组,也可以是别的)

字节流:以字节为单位,每次次读入或读出是 8 位数据。可以读任何类型数据,图片、文件、音乐视频等。 (Java 代码接收数据只能为 byte 数组)

按照实际 IO 操作来分:

 输出流:从内存读出到文件。只能进行写操作。

 输入流:从文件读入到内存。只能进行读操作。

注意:输出流可以帮助我们创建文件,而输入流不会。

按照读写时是否直接与硬盘,内存等节点连接分:

节点流:直接与数据源相连,读入或读出。

l处理流:也叫包装流,是对一个对于已存在的流的连接进行封装,通过所封装的流的功能调用实现数据读写。如添加个 Buffering 缓冲区。(意思就是有个缓存区,等于软件和mysql 中的 redis) 注意:为什么要有处理流?主要作用是在读入或写出时,对数据进行缓存,以减少 I/O 的次数,以便下次更好更快的读写文件,才有了处理流。

字节流如何转为字符流?

字节输入流转字符输入流通过 InputStreamReader 实现,该类的构造函数可以传入 InputStream 对象。字节输出流转字符输出流通过 OutputStreamWriter 实现,该类的构造函数可以传入OutputStream 对象。

BIO、NIO、AIO 有什么区别

86BIO (Blocking I/O):同步阻塞 I/O 模式,数据的读取写入必须阻塞在一个线程内等待其 完成。在活动连接数不是特别高(小于单机 1000)的情况下,这种模型是比较不错的,可以 让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的I/O 处理模型来应对更高的并发量。

NIO (New I/O): NIO 是一种同步非阻塞的 I/O 模型,在 Java 1.4 中引入了 NIO 框架,对应 java.nio 包,提供了 Channel , Selector,Buffer 等抽象。NIO 中的 N 可以理解为 Non-blocking,不单纯是 New。它支持面向缓冲的,基于通道的 I/O 操作方法。NIO提供了与传统 BIO 模型中Socket 和 ServerSocket 相对应 de 的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞 I/O 来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。

AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版NIO 2,它是异步非阻塞的 IO 模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作 之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的 操作。AIO 是异步 IO 的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO 操作本身是同步的。查阅网上相关资料,我发现就目 前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

NIO 有哪些核心组件?

Channel Buffer SelectorChannel 和流有点类似。通过 Channel,我们即可以从 Channel 把数据写到 Buffer中,也可以把数据冲 Buffer 写入到 Channel,每个 Channel 对应一个 Buffer 缓冲区, Channel 会注册到 Selector。Selector 根据 Channel 上发生的读写事件,将请求交由某个空闲的线程处理,Selector 对应一个或多个线程,Channnel 和 Buffer 是可读可写的。  

什么是 Java 序列化,如何实现 Java 序列化

序列化就是一种用来处理对象流的机制,将对象的内容进行流化。可以对流化后的对象进 行读写操作,可以将流化后的对象传输于网络之间。 序列化是为了解决在对象流读写操作时所引发的问题 序列化的实现:将需要被序列化的类 实现 Serialize 接口,没有需要实现的方法,此接口只是为了标注对象可被序列化的,然后使 用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象, 再使用 ObjectOutputStream 对象的 write(Object obj)方法就可以将参数 obj 的对象写出。

如何实现对象克隆?

有两种方式:

1. 实现 Cloneable 接口并重写 Object 类中的 clone()方法;

2. 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度

克隆。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值