Java提供了哪几种IO方式

本文介绍了Java中的同步、异步、阻塞、非阻塞概念,详细解析了阻塞IO、非阻塞IO和多路复用IO模型。接着探讨了BIO、NIO和AIO的区别,BIO基于阻塞IO,NIO提供非阻塞IO并引入Selector,而AIO则实现了异步IO,允许程序在数据准备就绪时得到通知。

同步、异步、阻塞、非阻塞概念

  • 阻塞、非阻塞
    IO操作分两部分,发起IO请求和IO数据读写,阻塞、非阻塞主要是针对线程发起IO请求后,是否立即返回
  • 同步、异步
    针对IO数据读写定义的,读写数据过程不阻塞线程称为异步IO

阻塞IO模型

最传统的一种IO模型,在读写数据的过程中会发生阻塞现象,

当用户线程发出IO请求之后,内核会去查看数据是否准备就绪,如果没有准备就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU。

数据准备就绪后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block状态

比如 java.io 包 ,基于流模型实现,交互方式是同步,阻塞的方式,在读取输入流或写入输出流时候,在读,写动作完成之前,线程会一直阻塞

还有java.net下面提供的部分网络API,比如 Socket、ServerSocket、HttpURLConnection 也归类到同步阻塞 IO 类库,因为网络通信同样是 IO 行为

非阻塞IO模型

当用户线程发起一个read操作后,不需要等待,马上得到了一个结果,如果结果是error时,就表示数据还没有准备好,用户线程可以继续发送read操作,一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,它马上将数据拷贝到用户线程,然后返回

在非阻塞IO模型中用户线程需要不断询问内核数据是否就绪,也就是不会交出CPU,导致CPU占用率很高

多路复用IO模型

会有一个线程不断去轮询多个 socket 的状态,只有当 socket 真正有读写事件时,才真正调用实际的 IO 读写操作

多路复用IO比非阻塞IO模型效率的原因 :

  • 在非阻塞IO中不断询问socket状态是通过用户线程去进行的,而在多路复用IO中,轮询每个socket状态是内核进行的

BIO、NIO、AIO

  • BIO
    BIO属于阻塞IO模型,当监听到客户端连接请求时,为每个客户端创建一个新的线程进行链路处理,

    最大的问题是缺乏弹性伸缩能力,当访问量增加以后服务端的线程个数与客户端的并发访问数成1:1的正比关系,当线程数膨胀之后系统的性能将急剧下降,随着并发访问量的继续增大,系统将出现 : 线程堆栈溢出,线程创建失败等问题

    在这里插入图片描述

  • NIO
    NIO主要有三大核心部分:Channel、Buffer、Selector,

    Channel与流的区别是Channel是双向的

    传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer进行操作,数 据总是从Channel读取到Buffer中,或从Buffer写入到Channel中

    Selector用于监听多个通道的时间,因此单个线程可以监听多个数据通道

    由于JDK使用poll代替传统的Selector的实现,所以并没有最大连接数的限制,可以接入成千上万的客户端

    NIO的非阻塞
    使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。

    非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞 IO 的空闲时间用于在其它通道上执行 IO 操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
    在这里插入图片描述

  • AIO
    AIO是非阻塞异步IO,是连接注册读写事件和回调函数,读写方法异步,并且将结果主动通知程序
    可以使用future获取异步的结果
    不需要通过多路复用器轮询就可以实现异步读写,简化了NIO的编程模型
    在这里插入图片描述

### Java 中支持的 IO 模型及其特点 #### 1. 阻塞 I/O (Blocking I/O, BIO) 阻塞 I/O 是一种经典的 I/O 实现方式,在这种模式下,当应用程序发起读写请求时,线程会进入等待状态直到操作完成。这种方式适用于低并发场景下的简单应用开发。 - **优点**: 编码简单直观,易于理解和维护。 - **缺点**: 如果内核数据未准备就绪,则用户进程会被长时间挂起,从而造成资源浪费并降低系统的整体效率[^3]。 #### 2. 非阻塞 I/O (Non-blocking I/O, NIO) 非阻塞 I/O 的特点是调用不会使线程陷入休眠;即使没有立即的数据可供处理,函数也会迅速返回表明当前无任何新输入到达的状态值给调用者知道情况如何进展下去再做决定是否继续尝试获取更多消息等内容来满足业务逻辑上的需求。 - **实现位置**: 所有的 NIO 类都位于 `java.nio` 及其子包之下,并且重新定义了许多来自传统 `java.io` 包里的概念与功能[^2]。 - **适用场合**: 对于高负载环境或者需要频繁轮询多个文件描述符的情况特别有用因为这样可以减少不必要的上下文切换次数进而提升吞吐量水平达到更好的性能表现效果出来为止才行啊不然的话就会出现问题啦! #### 3. 新型异步 I/O (Asynchronous File Channel AIO) 这是 JDK7 开始引入的一种全新的 API 设计理念——即所谓的“真正的”异步 I/O 处理机制(尽管严格意义上讲它更接近事件驱动架构而非纯粹意义上的异步)。通过注册回调方法使得一旦某个特定条件达成之后便会自动触发相应的动作而无需显式地去检查每一个单独连接对象的状态变化过程到底处于哪个阶段当中去了呢?这样一来就可以极大地简化复杂网络通信协议栈的设计难度同时也提高了程序运行期间的整体稳定性程度哦~ - **区别说明**: 虽然有时人们习惯把 NIO 和 AIO 统称为 New IO ,但实际上两者之间存在本质差异主要体现在同步/异步以及阻塞与否这两个维度之上[^4]。 ```java // 示例代码展示如何创建一个简单的 AsynchronousFileChannel 并执行基本的操作 import java.nio.file.*; import java.nio.ByteBuffer; import java.util.concurrent.Future; public class AsyncIoExample { public static void main(String[] args) throws Exception{ Path path = Paths.get("example.txt"); try(AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.READ)){ ByteBuffer buffer = ByteBuffer.allocate(48); Future<Integer> result = channel.read(buffer,0); while(!result.isDone()){ System.out.println("Waiting..."); Thread.sleep(10); // Simulate waiting without blocking the thread. } int bytesRead = result.get(); System.out.println("Bytes read : "+bytesRead); } } } ``` #### 总结 每种类型的 IO 模型都有各自的优势和局限性,因此在实际项目规划初期就需要充分评估目标平台特性及预期工作负荷等因素后再做出合理的选择方案才是明智之举呀!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值