Handler源码分析之epoll机制
创始人
2025-06-01 11:57:07

分析epoll机制之前我们需要先明确一个概念什么是阻塞和非阻塞?

举个例子,假设你要收个快递,但你不知道快递小哥什么时候送,你又没有其他事可做,那么你可以去睡觉了(释放cpu资源),因为你知道快递小哥到了会打电话通知你,这个睡觉的状态就是阻塞。

同样,你要收个快递,但你不知道快递小哥什么时候送,但你放心不下这件事你不选择去睡觉,你每分钟都给快递小哥打电话问他到了没,你一直打电话询问这个状态就是非阻塞式忙轮询,虽然最终都收到了快递,但后者会很累(cpu一直在运行)java并发编程中的CAS也是这种原理。

而阻塞是一个和 I/O 相关的概念,这涉及一个操作系统级的操作epoll_wait,当读取磁盘文件时会有内存速度不匹配的问题,中间需要有个缓存过程,是从磁盘读到缓存,缓存满了,再从缓存中读数据,等待缓存满的时候就需要阻塞住先不读取。

再举个例子,当前有n个I/O事件,我们如何处理多个流?

没有阻塞概念的话,如下(是一段伪代码):

while(true){for(i -> stream[]){// 一直询问我可以读了吗?if i has data{read data until unalivaible     }}}

这种方式下,当所有的流都没数据的这段时间里,cpu只能一直跑for循环,但又没有数据可读,所以cpu一直在空转,耗费cpu资源而没有任何意义,那怎么解决这个问题呢?

阻塞就出现了:

while(true){//select是个Linux系统级操作,他会一直阻塞直到其中有一个或多个流可以读,再去执行下面的代码select(stream[])for(i -> stream[]){// 一直询问我可以读了吗?if i has data{read data until unalivaible     }}}

但是这个方式并不能确切的知道有几个流可读,我们只能无差别的去轮询所有的流,那怎么处理这个缺陷呢?随着Linux系统的升级,今天的主角epoll就出现了:

while(true){//select是个Linux系统级操作,他会一直阻塞直到其中有一个或多个流可以读,再去执行下面的代码active_stream = epoll_wait(stream[])for(i -> active_stream[]){read data until unalivaible     }}

epoll可以过滤出可以进行读写的流,而不用我们再去轮询了,此时我们对所有流的处理都是有意义的。

epoll是Linux内核中的一种可扩展IO事件处理机制。大量应用程序请求时能够获得较好的性能。

下面是几个epoll相关的几个方法:

int epoll_create(int size);
//创建一个epoll的句柄,size用来告诉内核需要监听的数目一共有多大int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event)
//epoll的事件注册函数int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
//参数events用来放从内核得到事件的集合,maxevents告知这个events有多大,这个maxevents的值不能
//大于创建epoll_create()时的size,timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法是永久阻塞)

到此epoll是什么大家已经有了基本概念和认知,下面再结合我们熟悉的Handler看看在Handler中是如何使用的:

MessageQueue.java//epoll的句柄,通过他能找到对应的epollprivate long mPtr;MessageQueue(boolean quitAllowed) {mQuitAllowed = quitAllowed;//native层去创建epollmPtr = nativeInit();}//以下是epoll相关的native方法private native static long nativeInit();//会调用epoll_create()private native static void nativeDestroy(long ptr);@UnsupportedAppUsageprivate native void nativePollOnce(long ptr, int timeoutMillis); //会调用epoll_wait(),这个函数里timeout就是这里传进去的private native static void nativeWake(long ptr);  //唤醒阻塞private native static boolean nativeIsPolling(long ptr);private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

epoll的了解就先到此为止了。

相关内容

热门资讯

cad打印线条粗细设置 cad... 004-线型(下)打印样式设置和线型文件使用一、线宽设置方法制图规范里边的线宽要求,我们已经定义好,...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...