您的位置 首页 java

Java的NIO为何能比BIO处理更多的连接?

IO是 网络编程 中最核心的内容之一,也是 网络通信 传输数据最基础的方式。在web1.0时代,绝大多数网络信息都是以静态内容呈现,传统的同步阻塞BIO传输是完全能够满足需求,但随着web2.0时代的到来,网民人数暴增,原先静态式的内容不再能满足需求,而是更注重于交互体验,比如用户可以登录,拥有个人信息,可以与其他用户进行通信,这就是web2.0时代。

Web2.0网民人数暴增,所以传统的同步阻塞BIO显然不能满足于交互通信 ,所以有了NIO同步非阻塞的诞生,当然还在此基础上优化的异步非阻塞AIO。

什么是IO?

Java 中I/O是以流为基础进行数据的输入输出的,所有数据被串行化输入输出流( 串行 化指的按照顺序),简单来说就是Java通过数据转换成 IO 流方式和外部设备进行交互,比如将一个文件从服务端发送给客户端。

BIO 和NIO

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

  • 同步 :一个任务的完成之前不能做其他操作,必须一直等待;好比打电话,你和朋友正在通电话中,在此期间其他人拨号进来都会提示通话中,只能等待你和你朋友结束通话后别人才能拨进。
  • 异步 :一个任务的完成之前,可以进行其他操作,好比使用聊天软件,当你和A聊天时,也可以同时和聊天,不必等到和A聊天结束才能和B进行聊天。
  • 阻塞 :是相对于 CPU 来说的, 挂起当前 线程 ,不能做其他操作只能等待
  • 非阻塞 :无须挂起当前线程,可以去执行其他操作

在客户端和服务端进行通信时,主要有两个步骤:

1、建立连接。

2、发送数据。

BIO

同步阻塞的IO,服务器实现一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,没处理完之前此线程不能做其他操作。比如在单核单线程的服务器,同一时刻,只能处理一个客户端的请求,处理完客户端请求返回数据释放连接后,才能处理其他新的请求。

现在只有单核单线程的服务器很少,那我服务器建立一个 线程池 使用 多线程 去处理,是不是就可以承载更多的客户端连接了?

确实,假如服务端建立一个500的线程池,那就可以同时处理500个连接,在web1.0时代这个连接数几乎都能cover住,但在如今的web2.0时代,全球几十亿网民用户来说,这个连接数远远不能满足场景的需要,即使再怎么提高服务器的硬件性能,也无法满足成千上万个客户同时连接,随便10000个客户端连接都直接把服务器干崩了。

NIO

同步非阻塞的IO,全称non-blocking IO,JDK1.4之后开始支持NIO,其是由Channel(管道)、Buffer(缓冲区)、Selector(选择器)三大核心部分构成的,可以解决传统BIO很多不足的问题;其核心的思想是将连接线程和数据处理线程分开,连接线程专门负责处理所有客户端的连接,数据处理线程专门处理客户端的数据请求;

其中最典型的就是 多路复用 模型,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理数据返回;

三大核心部分关系如上图所示:

  • 每个 Channel 对应一个 Buffer
  • Selector 对应一个线程,一个线程可以对应多个 Channel
  • 线程切换到那个 Channel 是由事件决定的
  • Selector 会根据不同的事件,在各个通道上切换

Selector (选择器)

  1. Java 的 NIO 使用了非阻塞的 I/O 方式。可以用一个线程处理若干个客户端连接,就会使用到 Selector(选择器)。
  2. Selector 能够检测到多个注册通道上是否有事件发生(多个 Channel 以事件的形式注册到同一个 selector),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。
  3. 只有在连接真正有读写事件发生时,才会进行读写,减少了系统开销,并且不必为每个连接都创建一个线程,不用维护多个线程。
  4. 避免了多线程之间上下文切换导致的开销。

Channel(管道)

NIO 的通道类似于流,但有如下区别:

  1. 通道是双向的可以进行读写,而BIO的流是单向的只能读,或者写。
  2. 通道可以实现异步读写数据。
  3. 通道可以从缓冲区读取数据,也可以写入数据到缓冲区

Buffer(缓冲区)

缓冲区本质上是一个可以读写数据的内存块,可以理解为是一个容器对象(含数组),该对象提供了一组方法,可以更轻松地使用内存块,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况。

Channel 提供从文件、网络读取数据的渠道,但是读取或者都必须经过 Buffer。

BIO和NIO区别

  1. BIO是阻塞的,NIO是非阻塞的
  2. BIO是面向流的,只能单向读写,NIO是面向缓冲(Buffer)的, 可以进行双向读写
  3. 使用BIO进行Socket连接时,因只能单向处理,所以每个连接都需新建一条线程,容易使服务器压力大,当并发数达到一定程度,服务器容易崩溃;而使用NIO进行BIO多路复用,使用一个线程来监听所有 Socket 连接,使用本线程或者其他线程进行数据处理,可以使得服务器同一时间可以处理更多的连接请求。

BIO和NIO的应用场景

BIO适用于连接数目较小且固定的架构,对服务器资源的要求较高,但其较简单,在并发数不大时,NIO并不比BIO性能好,主要是得益于每条线程处理一个连接,避免了线程的上下文切换,因此在一些小型的系统表现更佳。

NIO适用于链接数目多且链接比较短(轻操做)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,但是因为使用了同步非阻塞处理,所以能够一条线程处理多个客户端连接,因此能够让服务器并发数量提升成千上百倍。这里不得不提到大名鼎鼎 Netty 框架了,它是Java中的NIO的经典框架,是基于NIO的API基础上进行了封装,让开发者使用它轻松能开发一个高性能的服务器, 大家有空可以去看一下它的源码实现

文章来源:智云一二三科技

文章标题:Java的NIO为何能比BIO处理更多的连接?

文章地址:https://www.zhihuclub.com/183644.shtml

关于作者: 智云科技

热门文章

网站地图