从操作系统内核看Java非阻塞IO事件检测

简介: 非阻塞服务器模型最重要的一个特点是,在调用读取或写入接口后立即返回,而不会进入阻塞状态。在探讨单线程非阻塞IO模型前必须要先了解非阻塞情况下Socket事件的检测机制,因为对于非阻塞模式最重要的事情是检测哪些连接有感兴趣的事件发生,一般会有如下三种检测方式。

非阻塞服务器模型最重要的一个特点是,在调用读取或写入接口后立即返回,而不会进入阻塞状态。在探讨单线程非阻塞IO模型前必须要先了解非阻塞情况下Socket事件的检测机制,因为对于非阻塞模式最重要的事情是检测哪些连接有感兴趣的事件发生,一般会有如下三种检测方式。

应用程序遍历socket检测

如图所示,当多个客户端向服务器请求时,服务器端会保存一个socket连接列表,应用层线程对socket列表进行轮询尝试读取或写入。对于读取操作,如果成功读取到若干数据则对读取到的数据进行处理,读取失败则下个循环再继续尝试;对于写入操作,先尝试将数据写入指定的某个socket,写入失败则下个循环再继续尝试。

这里写图片描述

这样看来,不管多少个socket连接都可以被一条线程管理起来,一条线程负责遍历这些socket列表,不断地尝试读取或写入数据,很好地利用了阻塞的时间,处理能力得到提升。但这种模型需要在应用程序中遍历所有的socket列表,同时需要处理数据的拼接,连接空闲时可能也会占用较多CPU资源,不适合实际使用。对此改进是使用事件驱动的非阻塞方式。

内核遍历socket的事件检测

这种方式将socket的遍历工作交给了操作系统内核,对socket遍历的结果组织成一系列的事件列表并返回应用层处理。对于应用层,他们需要处理的对象就是这些事件,这就是其中一种事件驱动的非阻塞方式的实现。

如图所示,服务器端有多个客户端连接,应用层向内核请求读写事件列表。内核遍历所有socket并生成对应的可读列表readList和可写列表writeList,readList标明了每个socket是否可读,例如socket1的值为1,表示可读,socket2的值为0,表示不可读。writeList则标明了每个socket是否可写。应用层遍历读写事件列表readList和writeList,做相应的读写操作。

这里写图片描述

内核遍历socket的方式已经不用在应用层对所有socket进行遍历,将遍历工作下移到内核层,这种方式有助于提高检测效率。但是它需要将所有连接的可读事件列表和可写事件列表传到应用层,假如socket连接数量大起来的话,列表从内核复制到应用层也是不小的开销。另外,当活跃连接较少时,内核与应用层之间存在很多无效的数据拷贝,因为它是将活跃和不活跃的连接状态都拷贝到应用层了。

内核基于回调的事件检测

通过遍历的方式检测socket是否可读可写是一种效率比较低的方式,不管是在应用层遍历还是在内核遍历。所以需要另外一种机制来优化遍历的方式,那就是回调函数。内核中socket都对应一个回调函数,当客户端往socket发送数据时,内核从网卡接收数据后就会调回调函数将此socket作为可读事件加入到事件列表中。应用层获取此事件列表即可得到所有感兴趣的事件。

如图所示,服务器端有多个客户端socket连接,首先应用层告诉内核每个socket感兴趣的事件;接着当客户端发送数据过来时,对应会有一个回调函数,内核从网卡复制数据成功后即调回调函数将socket1作为可读事件event1加入到事件列表,同样地,内核发现网卡可写时就将socket2作为可写事件event2添加到事件列表中;最后,应用层向内核请求读写事件列表,内核将包含了event1和event2的事件列表返回应用层,应用层通过遍历事件列表得知socket1有数据待读取,于是进行读操作,而socket2则可以写入数据。

这里写图片描述

这种方式由操作系统内核维护客户端的所有连接并通过回调函数不断更新可读可写事件列表,而应用层线程只要遍历这些事件列表即可知道可读取或可写入的连接,进而对这些连接进行读写操作。极大提高了检测效率,自然处理能力也更强。

上面介绍了三种非阻塞的事件检测机制,对于Java来说,非阻塞IO的实现完全是基于操作系统内核的非阻塞IO,它将操作系统的非阻塞IO的差异屏蔽了并提供统一的API,让我们不必关心操作系统。JDK会帮我们选择非阻塞IO的实现方式,例如对于Linux系统,在支持epoll的情况下JDK会优先选择用epoll实现Java的非阻塞IO。这种非阻塞方式的事件检测机制就是效率最高的“内核基于回调的事件检测”。

========广告时间========

鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以到 https://item.jd.com/12185360.html 进行预定。感谢各位朋友。

为什么写《Tomcat内核设计剖析》

=========================

目录
相关文章
|
3月前
|
设计模式 算法 安全
实时操作系统(RTOS)深度解析及Java实现初探
【10月更文挑战第22天】实时操作系统(RTOS,Real-Time Operating System)是一种能够在严格的时间限制内响应外部事件并处理任务的操作系统。它以其高效、高速、可靠的特点,广泛应用于工业自动化、航空航天、医疗设备、交通控制等领域。本文将深入浅出地介绍RTOS的相关概念、底层原理、作用与功能,并探讨在Java中实现实时系统的方法。
116 1
|
3天前
|
Java 开发者 Spring
java springboot监听事件和处理事件
通过上述步骤,开发者可以在Spring Boot项目中轻松实现事件的发布和监听。事件机制不仅解耦了业务逻辑,还提高了系统的可维护性和扩展性。掌握这一技术,可以显著提升开发效率和代码质量。
65 33
|
5天前
|
Java 开发者 Spring
java springboot监听事件和处理事件
通过上述步骤,开发者可以在Spring Boot项目中轻松实现事件的发布和监听。事件机制不仅解耦了业务逻辑,还提高了系统的可维护性和扩展性。掌握这一技术,可以显著提升开发效率和代码质量。
31 13
|
9天前
|
Java Spring
Java Spring Boot监听事件和处理事件
通过上述步骤,我们可以在Java Spring Boot应用中实现事件的发布和监听。事件驱动模型可以帮助我们实现组件间的松耦合,提升系统的可维护性和可扩展性。无论是处理业务逻辑还是系统事件,Spring Boot的事件机制都提供了强大的支持和灵活性。希望本文能为您的开发工作提供实用的指导和帮助。
51 15
|
11天前
|
Java 开发者 Spring
Java Springboot监听事件和处理事件
通过这些内容的详细介绍和实例解析,希望能帮助您深入理解Spring Boot中的事件机制,并在实际开发中灵活应用,提高系统的可维护性和扩展性。
38 7
|
2月前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
2月前
|
安全 Linux 网络安全
nmap 是一款强大的开源网络扫描工具,能检测目标的开放端口、服务类型和操作系统等信息
nmap 是一款强大的开源网络扫描工具,能检测目标的开放端口、服务类型和操作系统等信息。本文分三部分介绍 nmap:基本原理、使用方法及技巧、实际应用及案例分析。通过学习 nmap,您可以更好地了解网络拓扑和安全状况,提升网络安全管理和渗透测试能力。
211 5
|
2月前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
56 6
|
3月前
|
安全 Java Python
基于python-django的Java网站全站漏洞检测系统
基于python-django的Java网站全站漏洞检测系统
42 0
|
3月前
|
Java C#
Java的监听处理事件--小球移动案例
Java的监听处理事件--小球移动案例
24 0