zoukankan      html  css  js  c++  java
  • Java NIO 选择器(Selector)的内部实现(poll epoll)

    http://blog.csdn.net/hsuxu/article/details/9876983

    之前强调这么多关于linux内核的poll及epoll,无非是想让大家先有个认识:


    Java NIO中的选择器依赖操作系统内核的这些系统调用,我们这里只讲解与linux内核相关的NIO实现,当然,windows或其他操作系统实现大体上是类似的,相信大家也可以触类旁通。


    那么,本文从这里将从简到难,一步一步为大家讲解选择器的点点滴滴吧。


    选择器的宏观理解
    “有这么一种检查员,她工作在养鸡场,每天的工作就是不停的查看特定的鸡舍,如果有鸡生蛋了,或者需要喂食,或者有鸡生病了,就把相应信息记录下来,这样一来,鸡舍负责人想知道鸡舍的情况,只需要到检查员那里查询即可,当然,鸡舍负责人得事先告知检查员去查询哪些鸡舍。“


    以上这段话即为选择器所做工作的一个比喻,实际上选择器为通道服务,通道事先告诉选择器:“我对某些事件感兴趣,如可读、可写等“,选择器在接受了一个或多个通道的委托后,开始选择工作,它的选择工作就完全交给操作系统,linux下即为poll或epoll。


    选择器的创建
    当调用Selector.open()时,选择器通过专门的工厂SelectorProvider来创建Selector的实现,SelectorProvider屏蔽了不同操作系统及版本创建实现的差异性。具体实现代码如下:


    java.nio.channels.Selector




    public static Selector open() throws IOException {
        return SelectorProvider.provider().openSelector();
    }
    因为SelectorProvider本身为一个抽象类,通过调用provider()提供对应的Provider实现,如PollSelectorProvider、EPollSelectorProvider


    java.nio.channels.spi.SelectorProvider


    public static SelectorProvider provider() {
    synchronized (lock) {
        if (provider != null)
        return provider;
        return (SelectorProvider)AccessController
        .doPrivileged(new PrivilegedAction() {
            public Object run() {
                if (loadProviderFromProperty())
                return provider;
                if (loadProviderAsService())
                return provider;
                provider = sun.nio.ch.DefaultSelectorProvider.create();
                return provider;
            }
            });
    }
    }
    默认的Provider实现即为DefaultSelectorProvider,通过调用create(),得到具体的SelectorProvider


    sun.nio.ch.DefaultSelectorProvider




    public static SelectorProvider create() {
    PrivilegedAction pa = new GetPropertyAction("os.name");
    String osname = (String) AccessController.doPrivileged(pa);
        if ("SunOS".equals(osname)) {
            return new sun.nio.ch.DevPollSelectorProvider();
        }
     
        // use EPollSelectorProvider for Linux kernels >= 2.6
        if ("Linux".equals(osname)) {
            pa = new GetPropertyAction("os.version");
            String osversion = (String) AccessController.doPrivileged(pa);
            String[] vers = osversion.split("\.", 0);
            if (vers.length >= 2) {
                try {
                    int major = Integer.parseInt(vers[0]);
                    int minor = Integer.parseInt(vers[1]);
                    if (major > 2 || (major == 2 && minor >= 6)) {
                        return new sun.nio.ch.EPollSelectorProvider();
                    }
                } catch (NumberFormatException x) {
                    // format not recognized
                }
            }
        }
     
        return new sun.nio.ch.PollSelectorProvider();
    }
    这是linux操作系统下的DefaultSelectorProvider的实现,可以看到,如果内核版本>=2.6则,具体的SelectorProvider为EPollSelectorProvider,否则为默认的PollSelectorProvider


    结合上文,可以猜测一下EPollSelectorProvider提供的Selector肯定是与内核epoll有关的,PollSelectorProvider提供的
    Selector肯定是与poll有关的。的确如此:


    sun.nio.ch.EPollSelectorProvider




    public AbstractSelector openSelector() throws IOException {
        return new EPollSelectorImpl(this);
    }
    sun.nio.ch.PollSelectorProvider


    public AbstractSelector openSelector() throws IOException {
        return new PollSelectorImpl(this);
    }

  • 相关阅读:
    P1311 选择客栈 模拟 ( + st表)
    P2656 采蘑菇 tarjan + spfa
    送别
    10.16互测题 贪心+数论
    poj 2823 Sliding Window 单调队列
    P1036 选数 dfs
    P3370 【模板】字符串哈希
    A Tear or A Smile?
    KMP 算法
    jQuery 中 attr 和 prop 的区别
  • 原文地址:https://www.cnblogs.com/jukan/p/5272257.html
Copyright © 2011-2022 走看看