Java IO:BIO和NIO差别及各自应用场景

转载请注明出处:jiq?钦‘s technical Blog - 季义钦

引言

BIO和NIO是两种不同的网络通信模型,现现在NIO已经大量应用在Jetty、ZooKeeper、Netty等开源框架中。

一个面向流、一个面向缓冲区

一个是堵塞式的、一个非堵塞

一个没有io多路复用器、一个有

以下通过一个样例解释两者差别:

假设当前服务端程序须要同一时候从与多个client建立的连接读取数据。

使用BIO

假设採用堵塞式IO。单线程情况下。处理者线程可能堵塞在当中一个套接字的read上,导致还有一个套接字即使准备好了数据也无法处理。这个时候解决办法就是针对每个套接字。都新建一个线程处理其数据读取。

所以说,在BIO工作模式下,服务端程序要想同一时候处理多个套接字的数据读取,在等待接收连接请求的主线程之外,还要为每个建立好的连接分配一个新的线程进行处理。

使用NIO

轮询方式

假设将套接字读操作换成非堵塞的,那么仅仅须要一个线程就能够同一时候处理套接字,每次检查一个套接字。有数据则读取,没有则检查下一个。由于是非堵塞的。所以运行read操作时若没有数据准备好则马上返回。不会发生堵塞。

 

I/O多路复用

这样的轮询的方式缺点是浪费CPU资源。大部分时间可能都是无数据可读的,不必仍不间断的重复运行read操作,I/O多路复用(IOmultiplexing)是一种更好的方法。调用select函数时。其内部会维护一张监听的套接字的列表,其会一直堵塞直到当中某一个套接字有数据准备好才返回。并告诉是哪个套接字可读,这时再调用该套接字的read函数效率更高。

所以基本能够觉得 “NIO = I/O多路复用 + 非堵塞式I/O”,大部分情况下是单线程。但也有超过一个线程实现NIO的情况

NIO三种模型

上面所讲到的仅仅须要一个线程就能够同一时候处理多个套接字,这仅仅是当中的一种单线程模型,是一种较为极端的情况。NIO主要包括三种线程模型:

1) Reactor单线程模型

2) Reactor多线程模型

3)主从Reactor多线程模型

Reactor单线程模型:

单个线程完毕全部事情包括接收client的TCP连接请求,读取和写入套接字数据等。

对于一些小容量应用场景。能够使用单线程模型。可是对于高负载、大并发的应用却不合适。主要原因例如以下:

1) 一个NIO线程同一时候处理成百上千的链路,性能上无法支撑,即便NIO线程的CPU负荷达到100%,也无法满足海量消息的编码、解码、读取和发送;

2) 当NIO线程负载过重之后。处理速度将变慢,这会导致大量client连接超时,超时之后往往会进行重发。这更加重了NIO线程的负载,终于会导致大量消息积压和处理超时,NIO线程会成为系统的性能瓶颈;

3) 可靠性问题:一旦NIO线程意外跑飞,或者进入死循环,会导致整个系统通信模块不可用。不能接收和处理外部消息,造成节点故障。

为了解决这些问题。演进出了Reactor多线程模型。

Reactor多线程模型:

Rector多线程模型与单线程模型最大的差别就是有一组NIO线程处理真实的IO操作。

Reactor多线程模型的特点:

1) 有专门一个NIO线程-Acceptor线程用于监听服务端,接收client的TCP连接请求;

2) 网络IO操作-读、写等由一个NIO线程池负责,线程池能够採用标准的JDK线程池实现。它包括一个任务队列和N个可用的线程,由这些NIO线程负责消息的读取、解码、编码和发送;

3) 1个NIO线程能够同一时候处理N条链路。可是1个链路仅仅相应1个NIO线程,防止发生并发操作问题。

在绝大多数场景下,Reactor多线程模型都能够满足性能需求;可是,在极特殊应用场景中。一个NIO线程负责监听和处理全部的client连接可能会存在性能问题

比如百万client并发连接,或者服务端须要对client的握手消息进行安全认证,认证本身很损耗性能。在这类场景下,单独一个Acceptor线程可能会存在性能不足问题,为了解决性能问题。产生了第三种Reactor线程模型-主从Reactor多线程模型。

即从单线程中由一个线程即监听连接事件、读写事件、由完毕数据读写,拆分为由一个线程专门监听各种事件。再由专门的线程池负责处理真正的IO数据读写。

主从Reactor多线程模型

主从Reactor线程模型与Reactor多线程模型的最大差别就是有一组NIO线程处理连接、读写事件。

主从Reactor线程模型的特点是:服务端用于接收client连接的不再是个1个单独的NIO线程。而是一个独立的NIO线程池。Acceptor接收到clientTCP连接请求处理完毕后(可能包括接入认证等),将新创建的SocketChannel注冊到IO线程池(sub reactor线程池)的某个IO线程上,由它负责SocketChannel的读写和编解码工作。

Acceptor线程池仅仅仅仅用于client的登陆、握手和安全认证,一旦链路建立成功,就将链路注冊到后端subReactor线程池的IO线程上,由IO线程负责兴许的IO操作。

即从多线程模型中由一个线程来监听连接事件和数据读写事件,拆分为一个线程监听连接事件,线程池的多个线程监听已经建立连接的套接字的数据读写事件,另外和多线程模型一样有专门的线程池处理真正的IO操作。

各自适用场景

NIO适用场景

server须要支持超大量长时间连接。比方10000个连接以上,而且每个client并不会频繁地发送太多数据。比如总公司的一个中心server须要收集全国便利店各个收银机的交易信息。仅仅须要少量线程按需处理维护的大量长期连接。

Jetty、Mina、Netty、ZooKeeper等都是基于NIO方式实现。

BIO适用场景

适用于连接数目比較小。而且一次发送大量数据的场景,这样的方式对server资源要求比較高,并发局限于应用中。

时间: 2024-08-13 01:19:17

Java IO:BIO和NIO差别及各自应用场景的相关文章

java IO(BIO)、NIO、AIO

IO 服务端ServerSocket 客户端Socket 缺点每次客户端建立连接都会另外启一个线程处理.读取和发送数据都是阻塞式的. 如果1000个客户端建立连接将会产生1000个线程 Server端 package bhz.bio.test; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { private int port; priva

Java IO:BIO和NIO区别及各自应用场景

转载请注明出处:jiq?钦's technical Blog - 季义钦 引言 BIO和NIO是两种不同的网络通信模型,现如今NIO已经大量应用在Jetty.ZooKeeper.Netty等开源框架中. 下面通过一个例子解释两者区别: 假设当前服务端程序需要同时从与多个客户端建立的连接读取数据. 使用BIO 如果采用阻塞式IO,单线程情况下,处理者线程可能阻塞在其中一个套接字的read上,导致另一个套接字即使准备好了数据也无法处理,这个时候解决的方法就是针对每一个套接字,都新建一个线程处理其数据

【Java】 BIO与NIO以及AIO分析

一.BIO与NIO以及AIO的概念 BIO是同步阻塞式的IO NIO是同步非阻塞的IO (NIO1.0,JDK1.4) AIO是非同步非阻塞的IO(NIO2.0,JDK1.7) 二.BIO简单分析 1.简单分析 BIO是阻塞的IO,原因在于accept和read会阻塞.所以单线程的BIO是无法处理并发的. 2.案例 服务端: public class BioServer { public static void main(String[] args) throws IOException {//

java面试题之BIO、NIO、AIO的应用场景

定义: 1.BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时,服务器就启动一个线程来处理,如果这个连接不处理任何事情会造成不必要的线程开销,可以通过线程池机制改善. 2.NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理. 3.AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,即客户端的I/O请求都是先经过操作系统处理后,再通知服务器应用去启动线程进行处理.

JAVA中IO技术:BIO、NIO、AIO

1.同步异步.阻塞非阻塞概念 同步和异步是针对应用程序和内核的交互而言的. 阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值. 由上描述基本可以总结一句简短的话,同步和异步是目的,阻塞和非阻塞是实现方式. 1 同步 指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪 自己上街买衣服,自己亲自干这件事,别的事干不了.

JAVA - IO - IO的类型(AIO, BIO, NIO)

IO的方式通常分为几种,同步阻塞的BIO.同步非阻塞的NIO.异步非阻塞的AIO. 一.BIO 在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行. 二.NIO NIO本身是基于事件驱动思想来完成的,其主

Java BIO、NIO、AIO 学习

先来个例子理解一下概念,以银行取款为例: 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写). 异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS(银行卡和密码),OS需要支持异步IO操作API). 阻塞 : ATM排队取款,你只能等待(使用阻塞IO时,Java调用会一直阻塞到读写完成才返回). 非阻塞 : 柜台取款,取个号,然后坐在椅子上做其它事,等号广播会通知你办理,没到号你

【转】Java BIO、NIO、AIO 认知

摘要: 关于java的IO,我们很多人都停留在java原API的一些stream上面,那么在网络中提到的BIO.NIO.AIO等关键词,你是否明白这个词的含义,以及其基本的原理? 注:此文也是本搬砖者转自网络,觉得此问对三个类型的IO的形象讲解做的很好,所以翻出来和大家共同学习. 原创:http://stevex.blog.51cto.com/4300375/1284437 先来个例子理解一下概念,以银行取款为例: 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读

Java BIO、NIO、AIO基础概念

引用别人的例子理解一下概念,以银行取款为例. 同步与异步:这两个概念与消息的通知机制有关,也就是同步的情况下,是由处理消息者自己去等待消息是否被触发,而异步的情况下是由触发机制来通知处理消息者,. ① 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写). ② 异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS(银行卡和密码),OS需要支持异步IO操作API). 阻塞与非阻塞:与程