NIO--Selector
目錄
?
概述
Selector
SelectableChannel
SelectionKey
建立選擇器
使用選擇鍵
使用選擇器
選擇過程
停止選擇過程
管理選擇鍵
并發性
異步關閉能力
選擇過程的可擴展性
概述
Selector
選擇器類管理著一個被注冊的通道集合的信息和它們的就緒狀態。通道是和選擇器一起被注冊的,并且使用選擇器來更新通道的就緒狀態。
SelectableChannel
這個抽象類提供了實現通道的可選擇性所需要的公共方法。它是所有支持就緒檢查的通道類的父類。
SelectableChannel可以被注冊到Selector對象上,同時可以指定對那個選擇器而言,那種操作是感興趣的。一個通道可以被注冊到多個選擇器上,但對每個選擇器而言只能被注冊一次。
SelectionKey
選擇鍵封裝了特定的通道與特定的選擇器的注冊關系。選擇鍵對象被SelectableChannel.register( ) 返回并提供一個表示這種注冊關系的標記。
通道在被注冊到一個選擇器上之前,必須先設置為非阻塞模式(通過調用configureBlocking(false))。試圖注冊一個處于阻塞狀態的通道,register( )將拋出未檢查的IllegalBlockingModeException異常。試圖注冊一個已經關閉的SelectableChannel實例的話,也將拋出ClosedChannelException異常。
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();//非阻塞式,立即返回select數量,可能為0,清除wakeup的調用影響。public abstract int selectNow() throws IOException;//設置了超時的selectpublic abstract int select(long timeout) throws IOException;//阻塞式,僅當 最少返回一個channel,wakeup方法被調用,線程被中斷時返回。返回keys數量,可能為0.public abstract int select() throws IOException;//喚醒沒有返回的select操作,使立即返回。如果當前沒有select操作,則下次select操作會立即返回,觸發selectNow被調用。public abstract Selector wakeup();public abstract void close() throws IOException;} public abstract class SelectionKey { public static final int OP_READ ;public static final int OP_WRITE ;public static final int OP_CONNECT ;public static final int OP_ACCEPT ;public abstract SelectableChannel channel( ); public abstract Selector selector( ); public abstract void cancel( ); public abstract boolean isValid( ); public abstract int interestOps( ); public abstract void interestOps (int ops); public abstract int readyOps( );public final boolean isReadable( ) ;public final boolean isWritable( ) ;public final boolean isConnectable( ) ;public final boolean isAcceptable( ) ;public final Object attach (Object ob) ;public final Object attachment( ) ;}選擇器才是提供管理功能的對象,而不是可選擇通道對象。選擇器對象對注冊到它之上的通道執行就緒選擇,并管理選擇鍵。
對于鍵的interest(感興趣的操作)集合和ready(已經準備好的操作)集合的解釋是和特定的通道相關的。每個通道的實現,將定義它自己的選擇鍵類。在register( )方法中構造它并將它傳遞給所提供的選擇器對象。
建立選擇器
Selector selector = Selector.open( );
channel1.register (selector, SelectionKey.OP_READ);
channel2.register (selector, SelectionKey.OP_WRITE);
channel3.register (selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
?// Wait up to 10 seconds for a channel to become ready
?readyCount = selector.select (10000);
有四種被定義的可選擇操作:讀(read),寫(write),連接(connect)和接受(accept)。
并非所有的操作都在所有的可選擇通道上被支持。例如,SocketChannel不支持accept。試圖注冊不支持的操作將導致IllegalArgumentException。您可以通過調用validOps( )方法來獲取特定的通道所支持的操作集合。
使用選擇鍵
attach( )方法將在鍵對象中保存所提供的對象的引用。SelectionKey類除了保存它之外,不會將它用于任何其他用途。
attachment( )方法獲取與鍵關聯的附件句柄
SelectionKey key = channel.register (selector, SelectionKey.OP_READ, myObject);
等價于:
SelectionKey key = channel.register (selector, SelectionKey.OP_READ);
key.attach (myObject);
SelectionKey對象是線程安全的,但知道修改interest集合的操作是通過Selector對象進行同步的是很重要
使用選擇器
選擇過程
keys( )方法返回與選擇器關聯的已經注冊的鍵的集合,并且可能是空的.這個已注冊的鍵的集合不是可以直接修改的。并不是所有注冊過的鍵都仍然有效。
selectedKeys( )方法返回已經準備好的鍵的集合,有可能是空的。這是一個鍵的集合,每個鍵都關聯一個已經準備好至少一種操作的通道。每個鍵都有一個內嵌的ready集合,指示了所關聯的通道已經準備好的操作。
已取消的鍵的集合(Cancelled key set)是已注冊的鍵的集合的子集,這個集合包含了cancel( )方法被調用過的鍵(這個鍵已經被無效化),但它們還沒有被注銷。
在一個剛初始化的Selector對象中,這三個集合都是空的。
選擇操作步驟:
1.已取消的鍵的集合將會被檢查。如果它是非空的,每個已取消的鍵的集合中的鍵將從另外兩個集合中移除,并且相關的通道將被注銷。這個步驟結束后,已取消的鍵的集合將是空的。
2.已注冊的鍵的集合中的鍵的interest集合將被檢查。在這個步驟中的檢查執行過后,對interest集合的改動不會影響剩余的檢查過程。
一旦就緒條件被定下來,底層操作系統將會進行查詢,以確定每個通道所關心的操作的真實就緒狀態。直到系統調用完成為止,這個過程可能會使得調用線程睡眠一段時間,然后當前每個通道的就緒狀態將確定下來。對于那些還沒準備好的通道將不會執行任何的操作。對于那些操作系統指示至少已經準備好interest集合中的一種操作的通道,將執行以下兩種操作中的一種:
a.如果通道的鍵還沒有處于已選擇的鍵的集合中,那么鍵的ready集合將被清空,然后表示操作系統發現的當前通道已經準備好的操作的比特掩碼將被設置。
b.否則,也就是鍵在已選擇的鍵的集合中。鍵的ready集合將被表示操作系統發現的當前已經準備好的操作的比特掩碼更新。
3.步驟2可能會花費很長時間,特別是所激發的線程處于休眠狀態時。與該選擇器相關的鍵可能會同時被取消。當步驟2結束時,步驟1將重新執行,以完成任意一個在選擇進行的過程中,鍵已經被取消的通道的注銷。
4.select操作返回的值是ready集合在步驟2中被修改的鍵的數量,而不是已選擇的鍵的集合中的通道的總數。返回值不是已準備好的通道的總數,而是從上一個select( )調用之后進入就緒狀態的通道的數量。之前的調用中就緒的,并且在本次調用中仍然就緒的通道不會被計入,而那些在前一次調用中已經就緒但已經不再處于就緒狀態的通道也不會被計入。這些通道可能仍然在已選擇的鍵的集合中,但不會被計入返回值中。返回值可能是0。
停止選擇過程
wakeup( ),提供了使線程從被阻塞的select( )方法中優雅地退出的能力.
調用Selector對象的wakeup( )方法將使得選擇器上的第一個還沒有返回的選擇操作立即返回。如果當前沒有在進行中的選擇,那么下一次對select( )方法的一種形式的調用將立即返回。后續的選擇操作將正常進行。在選擇操作之間多次調用wakeup( )方法與調用它一次沒有什么不同。
如果只想喚醒一個睡眠中的線程,而使得后續的選擇繼續正常地進行。您可以通過在調用wakeup( )方法后調用selectNow( )方法來繞過這個問題。
管理選擇鍵
選擇是累積的。一旦一個選擇器將一個鍵添加到它的已選擇的鍵的集合中,它就不會移除這個鍵。并且,一旦一個鍵處于已選擇的鍵的集合中,這個鍵的ready集合將只會被設置,而不會被清理。
清理一個SelectKey的ready集合的方式是將這個鍵從已選擇的鍵的集合中移除。選擇鍵的就緒狀態只有在選擇器對象在選擇操作過程中才會修改
并發性
選擇器對象是線程安全的,但它們包含的鍵集合不是。通過keys( )和selectKeys( )返回的鍵的集合是Selector對象內部的私有的Set對象集合的直接引用。這些集合可能在任意時間被改變。已注冊的鍵的集合是只讀的。
異步關閉能力
選擇過程的可擴展性
?
總結
以上是生活随笔為你收集整理的NIO--Selector的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NIO--Channel
- 下一篇: Netty--Reactor模式