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);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM