Java BIO、NIO、AIO 学习

标签: Java BIO NIO AIO
原创作品,允许转载,转载时请务必以超链接形式标明文章  原始出处 、作者信息和本声明。否则将追究法律责任。 http://stevex.blog.51cto.com/4300375/1284437

前言:关于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先完成了再通知服务器应用去启动线程进行处理,


BIO、NIO、AIO适用场景分析:

  • BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。

  • NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。

  • AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。


另外,I/O属于底层操作,需要操作系统支持,并发也需要操作系统的支持,所以性能方面不同操作系统差异会比较明显。



2013-08-28 17:00:06
“一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作。
同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO。
阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。

同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪,而异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知。而阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值。
所以,IO操作可以分为3类:同步阻塞(即早期的IO操作)、同步非阻塞(NIO)、异步(AIO)。
同步阻塞:
在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。JAVA传统的IO模型属于此种方式。

同步非阻塞:
在此种方式下,用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。
异步:
此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序。”

这段话比较清楚


### JavaBIONIOAIO 的区别 #### 同步阻塞 I/O (BIO) 同步阻塞 I/O 是最传统的 I/O 模型。在这种模式下,当应用程序发起一个 I/O 请求时,调用线程会被挂起直到请求完成。这意味着如果当前线程正在处理某个耗时的 I/O 操作,则该线程无法继续执行其他任务。 对于服务器端开发而言,通常需要为每一个客户端连接创建一个新的线程来处理通信过程中的读写操作。这种方式虽然简单直观,但在高并发场景下的资源消耗非常大,因为每个活跃连接都需要占用独立的工作线程[^5]。 ```java ServerSocket server = new ServerSocket(port); while(true){ Socket client = server.accept(); // 此处会发生阻塞 } ``` #### 非阻塞 I/O (NIO) 非阻塞 I/O 则允许程序在发出 I/O 调用时不被阻塞,而是立即返回给调用方。具体来说,在 NIO 下可以通过 `Selector` 对象管理多个 Channel 实例的状态变化事件(如可读、可写)。一旦有就绪状态发生改变,就会触发相应的回调逻辑去处理实际的数据交换工作。这种机制大大提高了单个线程所能承载的最大并发量,并且降低了上下文切换带来的开销[^3]。 ```java // 创建 Selector 并注册感兴趣的事件类型 Selector selector = Selector.open(); serverChannel.configureBlocking(false); serverChannel.register(selector, SelectionKey.OP_ACCEPT); // 处理已准备好的 channel int readyChannels = selector.select(); if (readyChannels == 0) continue; Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while(keyIterator.hasNext()){ SelectionKey key = keyIterator.next(); if(key.isAcceptable()) { // handle accept event... } else if (key.isReadable()) { // handle read event... } ... } ``` #### 异步非阻塞 I/O (AIO/NIO.2) 自JDK 7引入以来,AIO 提供了一个更加高级别的抽象层用于构建高效的网络服务端应用。不同于之前的两种方式,这里所有的I/O操作均采用完全异步的方式运行——既不会阻塞也不会轮询查询结果;相反地,它们会在后台由操作系统负责调度直至完成后通知用户态的应用代码。开发者只需定义好完成处理器(`CompletionHandler`)即可轻松捕获到最终的结果反馈信息[^1]. ```java AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(); serverChannel.bind(new InetSocketAddress(port)); serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() { @Override public void completed(AsynchronousSocketChannel result, Void attachment) { System.out.println("New connection accepted"); ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); result.read(buffer, buffer, new ReadCompletionHandler(result)); } @Override public void failed(Throwable exc, Void attachment) { logger.log(Level.SEVERE,"Failed to accept a connection",exc); } }); ``` ### 应用场景分析 - **低并发环境**: 如果业务需求较为单一且预计访问压力不大,那么可以选择简单的 BIO 方案快速搭建原型系统; - **中等规模并发负载**: 当面对一定数量级的同时在线用户数时,建议考虑基于 NIO 构建的服务架构,利用多路复用技术提升吞吐率; - **大规模分布式集群部署**: 在追求极致性能表现的情况下,尤其是涉及到海量短链接频繁交互或是长时间保持长连接通讯的任务场景,应该优先评估是否适合迁移到支持全异步语义的新一代 API —— 即 AIO 上面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值