❶ java IO、NIO、AIO详解
在Java的学习过程中,我们首先需要理解几个关键概念:同步和异步的概念,以及阻塞与非阻塞的概念。同步意味着用户线程发起I/O请求后需要等待内核I/O操作完成才能继续执行,而异步则是用户线程在发起请求后仍可继续执行,内核I/O操作完成时会通知用户线程或调用其注册的回调函数。阻塞是指在发起I/O操作后线程需要等待操作完成,而非阻塞则是在发起后立即返回操作状态,无需等待完成。
Java的IO流基于java.io包实现,提供如File、输入输出流等基础功能,其特点是同步、阻塞的交互方式。虽然简单直观,但IO效率和扩展性受限,易成为性能瓶颈。同时,java.net中的Socket、ServerSocket、HttpURLConnection等API也被认为属于同步阻塞IO类库。
为解决上述问题,Java引入了NIO框架(java.nio包),在Java 1.4中首次出现,提供了Channel、Selector、Buffer等新抽象,允许构建多路复用、同步非阻塞IO程序。此框架提供了更接近操作系统底层的高性能数据操作方式。随着Java 7的NIO 2版本(也称为AIO),引入了异步非阻塞IO方式,即异步IO操作基于事件和回调机制,应用操作直接返回,后台处理完成后系统会通知相应线程进行后续工作。
NIO的核心组成部分包括Channel(通道)、Buffer(缓冲区)和Selector(选择器)。Channel用于读取和写入数据,类似于流,但通过Buffer处理数据,同时可双向操作,更好地反映操作系统真实情况。Buffer作为数据处理的中转池,用于存储从通道读取或准备写入通道的数据。使用Buffer读写数据通常包括写入数据、翻转缓冲区、从缓冲区读取数据以及清除或压缩缓冲区等步骤。
Selector是一个管理多个Channel的高效工具,允许通过一个线程处理大量并发连接,显着减少线程切换开销。创建和使用Selector涉及创建对象、注册Channel、访问准备就绪事件集合以及处理就绪的Channel等步骤。Selector的使用提高了线程的利用率和应用的扩展性。
当谈到异步IO(AIO),它在NIO的基础上更进一步,不依赖于IO操作准备好时的通知,而是当IO操作完成后主动通知应用,从而实现真正的非阻塞操作。AIO简化了IO编程,使操作更直接,无需等待操作准备,系统会在操作完成后调用预设的回调函数。在Java 1.7中,NIO 2版本引入了AIO,提供了和AsynchronousSocketChannel等异步通道,以及CompletionHandler接口来处理异步事件。
总结,Java IO流通过同步阻塞方式实现基础数据传输,NIO通过引入Channel、Buffer和Selector提供更高效、扩展性更强的IO处理方式,而AIO则进一步简化编程模型,提供非阻塞、异步的IO操作,显着提高了应用性能和可扩展性。
❷ BIO、NIO、AIO的区别和原理
本文主要讨论了IO模型在Java开发中的应用,特别是BIO、NIO、AIO三种模型的原理与区别。
BIO(Blocking I/O)模型是Java早期使用的IO模型,特点是同步并阻塞,服务器以一个连接对应一个线程的方式运行,这种方式虽然直观易懂,但资源消耗大,不适合处理大量并发连接。
NIO(Non-blocking I/O)模型则采用同步非阻塞的方式,服务器以一个请求对应一个线程的方式运行。当有多个连接同时进行I/O操作时,NIO模型通过多路复用器轮询并处理请求,这样可以有效减少线程数量,提高资源利用率。NIO模型适用于连接数量较多且操作较轻的场景。
AIO(Asynchronous I/O)模型,也称为NIO2,是一种异步非阻塞的IO模型。在AIO中,客户端的I/O请求由操作系统先完成,再通知应用启动线程进行处理。这样可以充分利用操作系统并发能力,但编程复杂度较高。AIO适用于连接数量多且操作较为复杂、资源密集型的场景,如相册服务器。
对于BIO模型的改进,可以采用多线程处理逻辑部分,将线程池与BIO模型结合,提高效率。在多CPU环境中,可以将Reactor模型分解为两部分,进一步优化性能。
NIO模型的改进主要集中在优化多路复用器的实现,以及利用epoll或select等高效事件管理机制,提高性能。同时,避免在连接没有数据时产生过多无用线程,降低资源消耗。
AIO模型则通过异步调用API的read或write方法,实现更高效的数据传输。在进行读写操作时,操作系统会主动通知应用程序,避免长时间阻塞,提高系统响应速度。AIO模型在处理大量并发连接和资源密集型操作时,能够显着提升性能。
IO处理流程方面,BIO模型中,线程会一直阻塞在读写操作上,直到数据完全传输。NIO模型使用多路复用器轮询并处理就绪的channel,实现更高效的并发处理。AIO模型中,应用调用非阻塞的accept方法,等待数据准备完成后回调处理响应操作。
综上所述,BIO、NIO和AIO模型在处理并发IO操作时各有优势,选择合适的模型取决于具体的应用场景和性能需求。了解这些模型的原理与实现方式,有助于在实际开发中做出更恰当的技术决策。
❸ Java NIO与IO的区别和比较
Java NIO和IO的主要区别如下:
1.NIO 的创建目的是为了让 Java 程序员可以实现高速 I/O 而无需编写自定义的本机代码。NIO 将最耗时的 I/O 操作(即填充和提取缓冲区)转移回操作系统,因而可以极大地提高速度。培仿判传统的IO操作属于阻塞型,严重影响程序的运行速度。
2,。流与块的比较。原来的大祥 I/O 库(在 java.io.*中) 与 NIO 最重要的区别是数据打包和传输的方式。正如前面提到的,原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。
面向流 的 I/O 系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费配改一个字节的数据。为流式数据创建过滤器非常容易。链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。不利的一面是,面向流的 I/O 通常相当慢。
3.一个 面向块 的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。
❹ java中bio nio aio的区别和联系
BIO是一个连接一个线程。
NIO是一个请求一个线程。
AIO是一个有效请求一个线程。
先来个例子理解一下概念,以银行取款为例:
同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写);
异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS(银行卡和密码),OS需要支持异步IO操作API);
阻塞 : ATM排队取款,你只能等待(使用阻塞IO时,Java调用会一直阻塞到读写完成才返回);
非阻塞 : 柜台取款,取个号,然后坐在椅子上做其它事,等号广播会通知你办理,没到号你就不能去,你可以不断问大堂经理排到了没有,大堂经理如果说还没到你就不能去(使用非阻塞IO时,如果不能读写Java调用会马上返回,当IO事件分发器会通知可读写时再继续进行读写,不断循环直到读写完成)
Java对BIO、NIO、AIO的支持:
Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,
❺ Java NIO和IO的区别
Java NIO和IO的主要区别如下:
1.NIO 的创建目的是为了让 Java 程序员可以实现高速 I/O 而无需编写自定义的本机代码。NIO 将最耗时的 I/O 操作(即填充和提取缓冲区)转移回操作系统,因而可以极大地提高速度。传统的IO操作属于阻塞型,严重影响程序的运行速度。
2,。流与块的比较。原来的 I/O 库(在 java.io.*中) 与 NIO 最重要的区别是数据打包和传输的方式。正如前面提到的,原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。
面向流 的 I/O 系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。为流式数据创建过滤器非常容易。链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。不利的一面是,面向流的 I/O 通常相当慢。
3.一个 面向块 的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。
❻ Java中IO与NIO的区别和使用场景
在java2以前,传统的socket IO中,需要为每个连接创建一个线程,当并发的连接数量非常巨大时,线程所占用的栈内存和CPU线程切换的开销将非常巨大。java5以后使用NIO,不再需要为每个线程创建单独的线程,可以用一个含有限数量线程的线程池,甚至一个线程来为任意数量的连接服务。由于线程数量小于连接数量,所以每个线程进行IO操作时就不能阻塞,如果阻塞的话,有些连接就得不到处理,NIO提供了这种非阻塞的能力。
NIO 设计背后的基石:反应器模式,用于事件多路分离和分派的体系结构模式。
反应器(Reactor):用于事件多路分离和分派的体系结构模式
通常的,对一个文件描述符指定的文件或设备, 有两种工作方式: 阻塞 与非阻塞 。所谓阻塞方式的意思是指, 当试图对该文件描述符进行读写时, 如果当时没有东西可读,或者暂时不可写, 程序就进入等待 状态, 直到有东西可读或者可写为止。而对于非阻塞状态, 如果没有东西可读, 或者不可写, 读写函数马上返回, 而不会等待 。
一种常用做法是:每建立一个Socket连接时,同时创建一个新线程对该Socket进行单独通信(采用阻塞的方式通信)。这种方式具有很高的响应速度,并且控制起来也很简单,在连接数较少的时候非常有效,但是如果对每一个连接都产生一个线程的无疑是对系统资源的一种浪费,如果连接数较多将会出现资源不足的情况。
另一种较高效的做法是:服务器端保存一个Socket连接列表,然后对这个列表进行轮询,如果发现某个Socket端口上有数据可读时(读就绪),则调用该socket连接的相应读操作;如果发现某个 Socket端口上有数据可写时(写就绪),则调用该socket连接的相应写操作;如果某个端口的Socket连接已经中断,则调用相应的析构方法关闭该端口。这样能充分利用服务器资源,效率得到了很大提高。
传统的阻塞式IO,每个连接必须要开一个线程来处理,并且没处理完线程不能退出。
非阻塞式IO,由于基于反应器模式,用于事件多路分离和分派的体系结构模式,所以可以利用线程池来处理。事件来了就处理,处理完了就把线程归还。而传统阻塞方式不能使用线程池来处理,假设当前有10000个连接,非阻塞方式可能用1000个线程的线程池就搞定了,而传统阻塞方式就需要开10000个来处理。如果连接数较多将会出现资源不足的情况。非阻塞的核心优势就在这里。
为什么会这样,下面就对他们做进一步细致具体的分析:
首先,我们来分析传统阻塞式IO的瓶颈在哪里。在连接数不多的情况下,传统IO编写容易方便使用。但是随着连接数的增多,问题传统IO就不行了。因为前面说过,传统IO处理每个连接都要消耗一个线程,而程序的效率当线程数不多时是随着线程数的增加而增加,但是到一定的数量之后,是随着线程数的增加而减少。这里我们得出结论,传统阻塞式IO的瓶颈在于不能处理过多的连接。
然后,非阻塞式IO的出现的目的就是为了解决这个瓶颈。而非阻塞式IO是怎么实现的呢?非阻塞IO处理连接的线程数和连接数没有联系,也就是说处理 10000个连接非阻塞IO不需要10000个线程,你可以用1000个也可以用2000个线程来处理。因为非阻塞IO处理连接是异步的。当某个链接发送请求到服务器,服务器把这个连接请求当作一个请求"事件",并把这个"事件"分配给相应的函数处理。我们可以把这个处理函数放到线程中去执行,执行完就把线程归还。这样一个线程就可以异步的处理多个事件。而阻塞式IO的线程的大部分时间都浪费在等待请求上了。
所谓阻塞式IO流,就是指在从数据流当中读写数据的的时候,阻塞当前线程,直到IO流可以
重新使用为止,你也可以使用流的avaliableBytes()函数看看当前流当中有多少字节可以读取,这样
就不会再阻塞了。