Java的中BIO、NIO、AIO-1

Java的中BIO、NIO、AIO-1

最近在项目中用到TCP通信来完成命令和运行结果的交互,用的是典型的TCP通信中的C/S架构,原因很简单:在业务需求低的环境下,这种架构简单、稳定还容易写。但是在实际部署的情况下,一直出现读不到数据的空指针异常,按说BIO模式开发的应该阻塞直到有数据读取,没有找到原因就变通写了一个消息队列,使用定时器每1s从定时器中拿数据,解决了这个问题。但是想想这种同步阻塞的形式,就想了解一下其他的模式:NIO、AIO。好了,啰嗦了好多,进入正题:

IO操作的基本概念

在说明BIO/NIO/AIO之前,要先弄明白这些概念和原理,什么是同步、异步,阻塞和非阻塞:

  • 同步
    在IO操作中,同步指的是用户进程出发IO操作并等待或者轮询的去查看IO操作是否就绪
  • 异步
    异步是指用户进程在出发IO操作之后,便开始做自己的事情,IO操作由系统来完成,而当IO操作完成的时候,用户进程会得到系统IO已经完成的通知。
  • 阻塞
    阻塞是指进程在访问数据(读写操作)的时候,如果得不到数据就一直等待直到数据就绪,进行下一步的操作。
  • 非阻塞
    非阻塞是指进程在访问数据(读写操作)的时候,进程会立即得到一个返回值,而不是一直等待下去。

总结起来同步异步是针对应用程序和内核的交互而言的,而阻塞和非阻塞是针对进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,就是一种读取和写入操作实现方式。更底层一点来说,同步和异步只是跟IO操作过程中进程的状态变化有关,而阻塞和非阻塞就是进程的两种状态。不要混淆了这些东西。

根据上面的基本概念,生成常见的四种IO模式:

  • 同步阻塞IO
  • 同步非阻塞IO
  • 异步阻塞IO
  • 异步非阻塞IO

下面来一一的说明这四种模型:

  • 同步阻塞IO
    同步阻塞IO是最简单的IO模型,在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。JAVA传统的IO模型属于此种方式!

同步阻塞IO

同步阻塞IO

  • 同步非阻塞IO
    在此种方式下,用户进程发起一个IO操作以后,就可以返回做其他的事情,但是用户进程需要时不时的去询问IO操作是否就绪,这就需要用户进程不断的去轮询、重复请求,这样会消耗大量的cpu资源。一般情况下很少使用这种模型,而是在其他IO模型中使用非阻塞IO这一特性。

同步非阻塞

同步非阻塞

  • 异步阻塞IO
    这种模式是指一个应用发起一个IO操作之后,不等待内核IO操作的完成,等IO操作真正完成的时候,应用程序会得到IO操作完成的通知。这其实就是同步和异步的最关键区别,同步必须等待或者主动的去询问IO操作是否完成,那为什么说是阻塞呢?因为此时是通过select系统调用完成的,而select函数本身的实现方式是阻塞的,采用select函数有两个好处就是它可以同时监听多个文件句柄,从而提升系统的并发性。

nio

nio

从上图中可以看到,用户首先将需要进行IO操作的socket添加到select中,然后阻塞等待select系统调用返回。当数据到达时,socket被激活,select函数返回。用户线程正式发起read请求,读取数据并继续执行。使用select函数的优点并不仅限于此。虽然上述方式允许单线程内处理多个IO请求,但是每个IO请求的过程还是阻塞的(在select函数上阻塞),平均时间甚至比同步阻塞IO模型还要长。如果用户线程只注册自己感兴趣的socket或者IO请求,然后去做自己的事情,等到数据到来时再进行处理,则可以提高CPU的利用率。

  • 异步非阻塞IO
    此种模式,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的处理完成之后,应用程序会得到IO操作完成的通知,此时用户只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读写操作已经由内核完成了。在IO多路复用模型中,事件循环将文件句柄的状态事件通知给用户线程,由用户线程自行读取数据、处理数据。而在异步IO模型中,当用户线程收到通知时,数据已经被内核读取完毕,并放在了用户线程指定的缓冲区内,内核在IO完成后通知用户线程直接使用即可。

aio

aio

上面简单的介绍了一下目前服务器编程中常见的几种IO模型,但是真正把这几种IO模型付诸实施的是几种设计模式:

  • C/S模式,这是经典的BIO通信模型。
  • Reactor模式 是异步阻塞IO的处理模型
  • Proactor模式 是异步非阻塞IO的处理模型

第二篇说明详细的说明这几种模式!!

猜你喜欢

转载自www.cnblogs.com/chailinbo/p/9226277.html