您的位置 首页 java

Java面试篇基础部分-Java中常用的I/O模型

阻塞I/O模型

阻塞式的I/O模型是一种非常常见的I/O模型机制,在进行数据读写操作的时候,客户端会发生阻塞等待。

工作流程如图所示,该用户线程一直阻塞,等待内存中的数据就绪;内存中的数据就绪之后,内核态的数据将拷贝到用户线程中,并且返回I/O的执行结果到用户线程。这个时候用户线程将会解除刚刚的阻塞状态并开始进行数据的处理。

比较典型的场景就是socket.read(),如果内核数据没有,Socket线程就会一直阻塞在read()中进行等待。

非阻塞I/O模型

非阻塞I/O模型是指用户线程在发起一个I/O操作之后,不需要阻塞就可以得到一个来自内核的反馈结果。如果内核的返回结果是false,表示内核数据还没有准备好,需要在稍后发起I/O操作。如果内核中的数据准备完成,并且收到用户请求的时候,内核就会立即将数据复制到用户的线程中,并且将数据复制的结果通知用户线程。

在非阻塞的I/O模型中,用户线程需要不断的访问内核数据是否就绪,在内核数据没有准备好的时候,用户线程可以进行处理其他的任务操作,在内核的数据准备好之后,立即获取数据并且进行响应的操作。如下所示。

 while(true){
data = socket.read();
  if(data==true){ // 内核数据准备完成
  // 获取到数据并且进行处理
  }else{
  //内核数据没有准备好,用户线程处理其他的任务操作
  }
}  

多路复用I/O模型

多路复用的I/O模型,是一种在并发编程中使用比较多的线程模型。Java中的NIO操作就是通过多路复用I/O实现的。在多路复用模型中有一个选择器(Selector)的线程会不断轮询Socket的状态,只有在Socket有读写事件的时候才会通知用户进行I/O操作。

在多路复用I/O模型中只有一个线程就可以管理多个Socket(阻塞I/O模型和非阻塞I/O模型需要为每一个Socket建立一个单独的线程处理该Socket上的数据),并且在真正有Socket读写事件的时候才会使用操作系统的资源,这样做可以大大节省系统资源操作。

JavaNIO操作在用户的每个线程中都通过selector.select()查询当前的通道是否有事件,如果没有则用户线程会一直阻塞。但是在多路复用I/O的方式下,一个线程管理了多个Socket通道,也就是说只有在Socket处于激活状态的时候才能使用读写操作。

所以,多路复用I/O模型在连接数众多的并且消息的体量不大的时候会有很大的优势,在物联网领域的,例如再车联网领域、智能家居领域等都会有很大的优势。

非阻塞I/O模型在每个用户线程中都需要进行Socket状态检查操作,而在多路复用模型中是在系统内核中进行Socket的状态检查,这个也是多路复用I/O模型比非阻塞模型高效的原因之一。

多路复用模型通过选择器(Selector)线程上通过轮询的方式检测多个Socket是否有对应的读写事件,并且逐个对事件进行处理。对于多路复用I/O模型来说,在数据较大的情况下,Selector线程就会成为瓶颈。,在实际操作中在多路复用的方法中一般是不支持做复杂的逻辑运算,它只负责进行数据的读写操作。

信号量驱动I/O模型

在信驱动I/O模型中,当用户线程发起一个I/O请求操作的时候,系统会为该请求对应一个Socket注册的信号函数,然后用户线程可以继续执行其他的业务逻辑;

在内核数据就绪的时候,系统会发送一个对应的信号量到用户的线程中,用户线程接收到信号量之后,会在信号函数中调用对应的I/O进行读写,完成实际的I/O操作。

异步I/O模型

在异步I/O模型中,用户线程会发起一个asynchronous read 操作到内核,内核在收到了对应的请求之后会立即返回对应的判断状态,来说明是否成功发起请求。在这个过程中用户线程不会发生任何的阻塞,接下来,内核会等待数据准备完成并且将数据复制到用户线程中,在数据复制完成之后,内核态会发送一个成功的标识到用户线程,然后用户线程进行读写操作。

在异步的I/O模型中,用户线程不需要关心整个的I/O操作是如何进行的,只需要发情一个请求,然后等待内核返回成功还是失败的信号,说明I/O操作已经完成,直接使用数据就可以了。

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

文章标题:Java面试篇基础部分-Java中常用的I/O模型

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

关于作者: 智云科技

热门文章

网站地图