《Java 源碼分析》:Java NIO 之 SelectionKey
在ServerSocketChannel源碼分析中我們知道當把一個channel註冊到指定的Selector上時,
實際上就是將(channel,selector)封裝成了一個SelectionKey對象,並將此對象儲存在了Selector對象中。
SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);
在Java NIO 的一些小Demo中,我們常常會看見這樣的代碼:
// 當註冊事件到達時,方法返回,否則該方法會一直阻塞 selector.select(); // 獲得selector中選中的相的迭代器,選中的相為註冊的事件 Set<SelectionKey> set = selector.selectedKeys(); Iterator<SelectionKey> ite = set.iterator(); while(ite.hasNext()){ SelectionKey selectionKey = (SelectionKey) ite.next(); // 刪除已選的key 以防重負處理 ite.remove(); if(selectionKey.isAcceptable()){//如果有用戶端串連進來 //先拿到這個SelectionKey裡面的ServerSocketChannel。 ServerSocketChannel serverSocketChannel = (ServerSocketChannel)selectionKey.channel(); // do something.... } }
今天我們就來看下這個類.
SelectionKeyImpl類中的幾個重要屬性如下:
final SelChImpl channel; 所擁有的channel對象,該屬性是包私人的 final SelectorImpl selector; 所擁有的selector對象,該屬性是包私人的 // Index for a pollfd array in Selector that this key is registered with private int index; //其值表示該SelectionKeyObject Storage Service在與其關聯的Selector對象中所在的位置 private volatile int interestOps; //集合 private int readyOps;
構造方法
SelectionKeyImpl(SelChImpl ch, SelectorImpl sel) { channel = ch; selector = sel; }
以下是這個類中用來擷取該對象中所關聯的 channel、selector的方法
public SelectableChannel channel() { return (SelectableChannel)channel; } public Selector selector() { return selector; } int getIndex() { // package-private return index; } void setIndex(int i) { // package-private index = i; }
都比較簡單,容易理解哈。
在編程中我們使用channel.register(selector,interestSet)方法來將channel註冊到指定的selector中。這個方法的第二個參數。這是一個“interest集合”,意思是在通過Selector監聽此Channel時對什麼事件感興趣。可以監聽四種不同類型的事件:
1、Connect
2、Accept
3、Read
4、Write
通道channel觸發了一個事件的意思是該事件已經就緒。所以,如果某個channel成功串連到另一個伺服器稱為“串連就緒”。如果一個ServerSocketChannel準備好接收新進入的串連稱為“接收就緒”。如果一個有資料可讀的通道可以說是“讀就緒”。等待寫資料的通道可以說是“寫就緒”。
這四種事件用SelectionKey的四個常量來表示,如下:
1、SelectionKey.OP_CONNECT
2、SelectionKey.OP_ACCEPT
3、SelectionKey.OP_READ
4、SelectionKey.OP_WRITE
如果你對不止一種事件感興趣,那麼可以用“位或”操作符將常量串連起來,如下:
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
在SelectionKey類的源碼中我們可以看到如下的4中屬性,四個變數用來表示四種不同類型的事件:可讀、可寫、可串連、可接受串連
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;
SelectionKey類還提供了以下幾個方法用來檢測channel中什麼事件或操作已經就緒
//測試此通道是否可讀 public final boolean isReadable() { return (readyOps() & OP_READ) != 0; } //測試此通道是否可讀 public final boolean isWritable() { return (readyOps() & OP_WRITE) != 0; } //檢查串連是否完成 public final boolean isConnectable() { return (readyOps() & OP_CONNECT) != 0; } //測試這個SelectionKey對應的通道是否已經接受了一個新的Socket串連。 public final boolean isAcceptable() { return (readyOps() & OP_ACCEPT) != 0; }
小結
以上,我們就簡單的看了下SelectionKey類,SelectionKey類簡單來說就是一個輔助類,比較簡單。