NIO 之 ByteBuffer實現原理
NIO 之 Channel實現原理
BIO、NIO、AIO 內部原理分析服務器
Selector容許單線程處理多個 Channel。若是你的應用打開了多個鏈接(通道),但每一個鏈接的流量都很低,使用Selector就會很方便。例如,在一個聊天服務器中。ide
這是在一個單線程中使用一個Selector處理3個Channel的圖示:源碼分析
selector與channel關係spa
要使用Selector,得向Selector註冊Channel,而後調用它的select()方法。這個方法會一直阻塞到某個註冊的通道有事件就緒。一旦這個方法返回,線程就能夠處理這些事件,事件的例子有如新鏈接進來,數據接收等。操作系統
僅用單個線程來處理多個Channels的好處是,只須要更少的線程來處理通道。事實上,能夠只用一個線程處理全部的通道。對於操做系統來講,線程之間上下文切換的開銷很大,並且每一個線程都要佔用系統的一些資源(如內存)。所以,使用的線程越少越好。
Selector可以在單個線程中處理多個通道,這樣能夠減小多個線程形成上下文切換問題。.net
public abstract class Selector implements Closeable { protected Selector() { } public static Selector open() throws IOException { return SelectorProvider.provider().openSelector(); } public abstract boolean isOpen(); public abstract SelectorProvider provider(); public abstract Set<SelectionKey> keys(); public abstract Set<SelectionKey> selectedKeys(); public abstract int selectNow() throws IOException; public abstract int select(long timeout) throws IOException; public abstract int select() throws IOException; public abstract Selector wakeup(); public abstract void close() throws IOException;
Selector 是個抽象類,提供一個靜態的方法獲取Selector子類SelectorImpl的實例。線程
下面分析Selector的幾個方法3d
該方法是在 Channel的register方法中調用的。具體詳見NIO 之 Channel實現原理rest
register 方法code
這四種事件用SelectionKey的四個常量來表示:
SelectionKey.OP_CONNECT
SelectionKey.OP_ACCEPT
SelectionKey.OP_READ
SelectionKey.OP_WRITE
不一樣的 Channel 註冊到 Selector 後,就能夠隨時查詢 Selector ,找出哪些 Channel 已經準備好能夠進行處理。Channel 可能準備好上面註冊到 Selector 感興趣事件中的一個或多個。
public int select() throws IOException { return select(0); }
public int select(long timeout) throws IOException { if (timeout < 0) throw new IllegalArgumentException("Negative timeout"); return lockAndDoSelect((timeout == 0) ? -1 : timeout); }
public int selectNow() throws IOException { return lockAndDoSelect(0); }
上面三個 select方法底層都是調用 lockAndDoSelect 方法。
lockAndDoSelect方法的參數值 說明:
-1 : 一直阻塞,直到有就緒的 Channel 可處理
0 : 不阻塞
timout>0: 表示阻塞多長時間(timeout)
獲取全部註冊到 Selector 上的 SelectionKey public Set<SelectionKey> keys() { if (!isOpen() && !Util.atBugLevel("1.4")) throw new ClosedSelectorException(); return publicKeys; }
獲取全部註冊到 Selector 上就緒 Channel 的 SelectionKey 信息。
public Set<SelectionKey> selectedKeys() { if (!isOpen() && !Util.atBugLevel("1.4")) throw new ClosedSelectorException(); return publicSelectedKeys; }
SelectionKey 類結構以下:
public abstract class SelectionKey { protected SelectionKey() { } public static final int OP_READ = 1 << 0; public static final int OP_WRITE = 1 << 2; public static final int OP_CONNECT = 1 << 3; public static final int OP_ACCEPT = 1 << 4; //附件信息 private volatile Object attachment = null; .... }
public abstract SelectableChannel channel()
獲取channel對象
public abstract Selector selector()
獲取seletor對象
public abstract void cancel()
從 Selector 中取消註冊該Channel
public abstract int interestOps()
獲取該chennel 註冊到 selector 上的事件
public abstract SelectionKey interestOps(int ops)
修改註冊到 selector 上的事件
public abstract int readyOps()
是否讀就緒
讀就緒不等於可讀,若是沒有註冊讀事件是不能讀的。
public final boolean isReadable()
判斷是否可讀
public final boolean isWritable()
是否可寫
public final boolean isConnectable()
是否已經鏈接
public final Object attach(Object ob)
添加附件信息
public final Object attachment() 獲取附件信息