I/O一直是软件开发中的核心部分之一. 伴随着海量的数据增长和分布式系统的发展. IO扩展显得尤为重要.
幸运的是. Java经过多年的发展, IO机制也不断地完善, 虽然仍有某些不足, 但已经在实践中证明了其构建高扩展性应用的能力.
所以: Java提供了哪些IO方式? NIO如何实现多路复用的呢?
Java IO 方式有很多种,基于不同的 IO 抽象模型和交互方式,可以进行简单区分。
首先,传统的 java.io 包,它基于流模型实现,提供了我们最熟知的一些 IO 功能,比如File 抽象、输入输出流等。交互方式是同步、阻塞的方式,也就是说,在读取输入流或者写入输出流时, 在读, 写动作完成之前, 线程会一直阻塞在那里. 它们之间的调用是可靠的线性顺序.
很多时候, 也把java.net
下面提供的部分网络API, 比如Socket, ServerSocket, HttpURLConnection也归类到同步阻塞IO类库, 因为网络通信同样是IO行为.
第二, NIO(非阻塞IO):Java NIO是一种基于通道(Channel)和缓冲区(Buffer)的IO操作方式,它提供了非阻塞的IO操作。核心组件包括Selector
、Channel
和Buffer
,通过Selector
实现多路复用,使得单个线程可以同时处理多个通道的读写操作。[这个是Java1.4引入的nio框架. 提供了更接近操作系统底层的高性能数据操作方式].
第三. NIO.2(异步IO):在Java 7中引入的NIO.2(也称为AIO)提供了异步IO操作的支持,通过AsynchronousSocketChannel
、AsynchronousFileChannel
等类实现异步IO操作。异步IO不需要等待数据的读取或写入完成,而是通过回调或者Future
来处理IO操作的结果。
上面的分类方式, 就是一种常见的分类方式, 也就是所谓的BIO, NIO, NIO2[AIO].
当然, 在实际面试中, 从传统的IO到NIO, NIO2. 这其中的很多地方都可以扩展开来, 考察的知识点将会涉及到方方面面:
我想这些是当你面试的时候, 不得不准备的知识储备吧.
首先要区分一些基本的概念:
在Java中,同步操作是指当发起一个IO请求时,程序会一直等待IO操作完成,然后才能继续执行后续代码。这种方式会阻塞当前线程的执行。
异步操作是指当发起一个IO请求时,程序不需要等待IO操作完成,而是可以继续执行后续代码。IO操作通常在后台线程或专门的IO线程上执行,并通过回调或事件通知的方式来处理IO操作的结果。
简而言之,同步操作需要等待IO操作完成,而异步操作可以继续执行其他任务而无需等待。
在选择同步还是异步操作时,需要考虑到具体的应用场景和需求,以及对系统性能和并发能力的影响。
区分阻塞和非阻塞:
阻塞和非阻塞是描述在进行IO操作时程序的行为方式。
阻塞是指当程序发起一个IO请求时,程序会一直等待IO操作完成,而不能执行其他任务。在阻塞状态下,程序无法继续往下执行,直到IO操作完成或出现异常。
非阻塞是指当程序发起一个IO请求时,程序可以立即返回并继续执行后续代码,而不需要等待IO操作完成。在非阻塞状态下,程序可以进行其他任务或查询IO操作的状态,而不会被IO操作阻塞。
简单来说,阻塞是一种等待的状态,程序会一直等待IO操作完成;而非阻塞则是一种立即返回的状态,程序可以继续执行其他任务。
在选择阻塞还是非阻塞方式时,需要根据应用的需求和性能要求进行考虑。阻塞IO可以简单易用,但可能会造成程序的停顿和响应延迟;而非阻塞IO可以提高程序的并发性和响应性,但需要额外的编程和处理复杂性。
不能一概而论认为同步或阻塞就是低效,具体还要看应用和系统特征。
而对于java.io
下, 在日常开发中都已经很熟悉了。
IO 不仅仅是对文件的操作,网络编程中,比如 Socket 通信,都是典型的 IO 操作目标。
输入流、输出流(InputStream/OutputStream)是用于读取或写入字节的,例如操作图片文件。
而 Reader/Writer 则是用于操作字符,增加了字符编解码等功能,适用于类似从文件中读取或者写入文本信息。本质上计算机操作的都是字节,不管是网络通信还是文件读取,Reader/Writer 相当于构建了应用逻辑和原始数据之间的桥梁。
BufferedOutputStream 等带缓冲区的实现,可以避免频繁的磁盘读写,进而提高 IO 处理效率。这种设计利用了缓冲区,将批量数据进行一次操作,但在使用中千万别忘了flush。
尤其是涉及到资源的问题, 一定要记得关闭资源。
概况
NIO(New I/O)是Java提供的一种基于通道(Channel)和缓冲区(Buffer)的IO模型,相对于传统的流(Stream)模型,NIO提供了更高效的IO操作和更灵活的IO处理方式。
NIO的主要组成部分包括:
通道(Channel):通道是NIO中用于进行数据读写的对象,它可以与文件、套接字等进行交互。通道提供了高效的数据传输方式,并且可以实现非阻塞IO操作。
缓冲区(Buffer):缓冲区是NIO中用于存储数据的对象,它提供了一块内存区域用于读写数据。在NIO中,数据的读写都是通过缓冲区来进行的,缓冲区可以直接与通道交互,实现高效的数据传输。
选择器(Selector):选择器是NIO中用于监听多个通道事件的对象,它可以实现单线程管理多个通道的IO操作。通过选择器,程序可以在一个线程中监听多个通道上的事件,实现了单线程处理多个IO操作的能力。
NIO的基本工作原理是通过将数据从通道读取到缓冲区,或者将数据从缓冲区写入到通道。同时,使用选择器可以在一个线程中监听多个通道上的事件,实现了非阻塞的IO操作。
总结起来,NIO的主要组成部分包括通道、缓冲区和选择器,它们共同协作完成高效的IO操作。通过NIO,可以实现更灵活、高效的IO处理,适用于处理大量并发连接和高负载的场景。
NIO 能解决什么问题?
NIO(New I/O)在Java中提供了一种基于通道(Channel)和缓冲区(Buffer)的IO模型,相对于传统的流(Stream)模型,NIO具有以下优势和能够解决的问题:
非阻塞IO:NIO支持非阻塞IO操作,可以在等待IO完成的同时继续处理其他任务,提高系统的并发性和响应性。
高效的IO操作:NIO使用直接的缓冲区访问和通道交互,避免了传统IO模型中的数据拷贝操作,提高了IO操作的效率。
多路复用:通过选择器(Selector),NIO可以在单个线程中监听多个通道上的事件,实现了单线程处理多个IO操作,减少了线程切换的开销,提高了系统的吞吐量。
支持网络编程:NIO提供了对网络编程的支持,可以使用NIO进行网络通信,包括处理TCP连接、读写数据等操作。
可扩展性:NIO的模型可以很好地适应高并发的场景,通过适当的调整缓冲区和通道的数量,可以处理大量的并发连接。
具体的代码演示在这里
NIO 多路复用的局限性是什么呢?你遇到过相关的问题吗?
ok,那就这样。