`
goldendoc
  • 浏览: 25925 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Java NIO 的 wakeup 剖析

    博客分类:
  • nio
阅读更多

java NIO的实现中,有不少细节点非常有学习意义的,就好比下面的这个点:
Selector的 wakeup原理是什么?是如何实现的?

wakeup()

准确来说,应该是Selector的wakeup(),即Selector的唤醒,为什么要有这个唤醒操作呢?那还得从Selector的选择方式 来说明,前文已经总结过Selector的选择方式有三种:select()、select(timeout)、selectNow()。
selectNow的选择过程是非阻塞的,与wakeup没有太大关系。
select(timeout)和select()的选择过程是阻塞的,其他线程如果想终止这个过程,就可以调用wakeup来唤醒。

wakeup的原理

既然Selector阻塞式选择因为找到感兴趣事件ready才会返回(排除超时、中断),就给它构造一个感兴趣事件ready的场景即可。下图可以比较形象的形容wakeup原理:

Selector管辖的FD(文件描述符,linux即为fd,对应一个文件,windows下对应一个句柄;每个可选择Channel在创建的时 候,就生成了与其对应的FD,Channel与FD的联系见另一篇)中包含某一个FD A, A对数据可读事件感兴趣,当往图中漏斗端放入(写入)数据,数据会流进A,于是A有感兴趣事件ready,最终,select得到结果而返回。

wakeup在Selector中的定义如下:
public abstract Selector wakeup();

下面结合上图来追寻wakeup的实现:
linux下Selector默认实现为PollSelectorImpl,当内核版本大于2.6时,实现为EPollSelectorImpl,仅看这两者的wakeup方法,代码似乎完全一样:

 

 

public Selector wakeup() {
    synchronized (interruptLock) {
        if (!interruptTriggered) {
            pollWrapper.interrupt();
            interruptTriggered = true;
        }
    }
    return this;
}
 

window下Selector的实现为WindowsSelectorImpl,其wakeup实现如下:

 

public Selector wakeup() {
    synchronized (interruptLock) {
        if (!interruptTriggered) {
            setWakeupSocket();
            interruptTriggered = true;
        }
    }
    return this;
}
 

其中interruptTriggered为中断已触发标志,当pollWrapper.interrupt()之后,该标志即为true了;得益于这个标志,连续两次wakeup,只会有一次效果。

 

对比上图及上述代码,其实pollWrapper.interrupt()及setWakeupSocket()就是图中的往漏斗中倒水的过程,不 管windows也好,linux也好,它们wakeup的思想是完全一致的,不同的地方就在于实现的细节了,例如上图中漏斗与通道的链接部 分,linux下是采用管道pipe来实现的,而windows下是采用两个socket之间的通讯来实现的,它们都有这样的特性:1)都有两个端,一个 是read端,一个是write端,windows中两个socket也是一个扮演read的角色,一个扮演write的角色;2)当往write端写入 数据,则read端即可以收到数据;从它们的特性可以看出,它们是能够胜任这份工作的。

 

如果只想理解wakeup的原理,看到这里应该差不多了,不过,下面,想继续深入一下,满足更多人的好奇心。
先看看linux下PollSelector的具体wakeup实现,分阶段来介绍:

 

1) 准备阶段

PollSelector在构造的时候,就将管道pipe,及wakeup专用FD给准备好,可以看一下它的实现:

 

PollSelectorImpl(SelectorProvider sp) {
    super(sp, 1, 1);
    int[] fdes = new int[2];
    IOUtil.initPipe(fdes, false);
    fd0 = fdes[0];
    fd1 = fdes[1];
    pollWrapper = new PollArrayWrapper(INIT_CAP);
    pollWrapper.initInterrupt(fd0, fd1);
    channelArray = new SelectionKeyImpl[INIT_CAP];
}
 

 

IOUtil.initPipe,采用系统调用pipe(int fd[2])来创建管道,fd[0]即为ready端,fd[1]即为write端。
另一个需要关注的点就是pollWrapper.initInterrupt(fd0, fd1),先看一下它的实现:

 

void initInterrupt(int fd0, int fd1) {
    interruptFD = fd1;
    putDescriptor(0, fd0);
    putEventOps(0, POLLIN);
    putReventOps(0, 0);
}
 

以看到,initInterrupt在准备wakeup专用FD,因为fd0是read端fd,fd1是write端fd:
interruptFD被初始化为write端fd;
putDescriptor(0, fd0)初始化pollfd数组中的第一个pollfd,即指PollSelector关注的第一个fd,即为fd0;
putEventOps(0, POLLIN)初始化fd0对应pollfd中的events为POLLIN,即指fd0对可读事件感兴趣;
putReventOps(0, 0)只是初始化一下fd0对应的pollfd中的revents;

2) 执行阶段

有了前面的准备工作,就看PollArrayWrapper中的interrupt()实现:

 

public void interrupt() {
    interrupt(interruptFD);
}
 

interrupt是native方法,它的入参interruptFD即为准备阶段管道的write端fd,对应于上图,其实就是漏斗端,因此,就是不看其实现,也知道它肯定扮演着倒水的这个动作,看其实现:

 

JNIEXPORT void JNICALL
Java_sun_nio_ch_PollArrayWrapper_interrupt(JNIEnv *env, jobject this, jint fd)
{
    int fakebuf[1];
    fakebuf[0] = 1;
    if (write(fd, fakebuf, 1) < 0) {
         JNU_ThrowIOExceptionWithLastError(env,
                                          "Write to interrupt fd failed");
    }
}
 

可以看出,interrupt(interruptFD)是往管道的write端fd1中写入一个字节(write(fd, fakebuf, 1))。
是的,只需要往fd1中写入一个字节,fd0即满足了可读事件ready,则Selector自然会因为有事件ready而中止阻塞返回。

EPollSelector与PollSelector相比,其wakeup实现就只有initInterrupt不同,它的实现如下:

 

void initInterrupt(int fd0, int fd1) {
    outgoingInterruptFD = fd1;
    incomingInterruptFD = fd0;
    epollCtl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN);
}
 

epfd之前的篇章里已经讲过,它是通过epoll_create创建出来的epoll文件fd,epollCtl调用内核epoll_ctl实现了往epfd上添加fd0,且其感兴趣事件为可读(EPOLLIN)。
因此可以断定,EPollSelector与PollSelector的wakeup实现是一致的。


因为之前一直专注与分析linux下的Java NIO实现,忽略了windows下的选择过程等,这里突然讲解其wakeup实现似乎很突兀,所以打算后面专门起一篇来介绍windows下的NIO实 现,这里我们只需要理解wakeup原理,甚至自己去看看其wakeup实现,应该也没什么难度。

 

关于wakeup,这里还有两个疑问:
为什么wakeup方法返回Selector?
windows下也是有pipe的,为什么使用socket而不是使用pipe来实现wakeup的?

 

也欢迎大家留下自己的想法,一起讨论。

 

ps. 本文为作者原创(java nio 教程
请大家关注黄金档

分享到:
评论

相关推荐

    java NIO和java并发编程的书籍

    java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java...

    JavaNIO chm帮助文档

    Java NIO系列教程(一) Java NIO 概述 Java NIO系列教程(二) Channel Java NIO系列教程(三) Buffer Java NIO系列教程(四) Scatter/Gather Java NIO系列教程(五) 通道之间的数据传输 Java NIO系列教程(六)...

    java nio 包读取超大数据文件

    Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据...

    Java NIO英文高清原版

    Java NIO英文高清原版

    java NIO 中文版

    讲解了 JavaIO 与 JAVA NIO区别,JAVA NIO设计理念,以及JDK中java NIO中语法的使用

    Java NIO 中文 Java NIO 中文 Java NIO 中文文档

    Java NIO 深入探讨了 1.4 版的 I/O 新特性,并告诉您如何使用这些特性来极大地提升您所写的 Java 代码的执行效率。这本小册子就程序员所面临的有代表性的 I/O 问题作了详尽阐述,并讲解了 如何才能充分利用新的 I/O ...

    java NIO 视频教程

    Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。 Java NIO: Channels and Buffers(通道和缓冲区) 标准的IO基于字节流和字符流进行操作的,...

    java nio 实现socket

    java nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socket

    java nio中文版

    java NIO是 java New IO 的简称,在 jdk1.4 里提供的新 api 。 Sun 官方标榜的特性如下: – 为所有的原始类型提供 (Buffer) 缓存支持。 – 字符集编码解码解决方案。 – Channel :一个新的原始 I/O 抽象。 – 支持...

    java NIO技巧及原理

    java NIO技巧及原理解析,java IO原理,NIO框架分析,性能比较

    Java Nio selector例程

    java侧起server(NioUdpServer1.java),基于Java Nio的selector 阻塞等候,一个android app(NioUdpClient1文件夹)和一个java程序(UI.java)作为两个client分别向该server发数据,server收到后分别打印收到的消息...

    基于Java NIO实现五子棋游戏.zip

    基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现...

    java NIO.zip

    java NIO.zip

    java nio 读文件

    java nio 读文件,java nio 读文件

    java基于NIO实现Reactor模型源码.zip

    java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现...

    JAVA NIO 学习资料

    JAVA NIO学习资料JAVA NIO学习资料

    Java NIO实战开发多人聊天室

    01-Java NIO-课程简介.mp4 05-Java NIO-Channel-FileChannel详解(一).mp4 06-Java NIO-Channel-FileChannel详解(二).mp4 08-Java NIO-Channel-ServerSocketChannel.mp4 09-Java NIO-Channel-SocketChannel.mp4 ...

    java nio入门学习,两个pdf

    java nio入门学习,两个pdfjava nio入门学习,两个pdf

    Java NIO原理 图文分析及代码实现

    Java NIO原理 图文分析及代码实现

    Java NIO.pdf

    java nio编程 非阻塞模式的通信 电子书 带目录标签

Global site tag (gtag.js) - Google Analytics