|
4.1.1 選擇器,可選擇通道和選擇鍵類 現(xiàn)在,您也許還對這些用于就緒選擇的Java成員感到困惑。讓我們來區(qū)分這些活動的零件并了解它們是如何交互的吧。圖 4-1 的UML圖使得情形看起來比真實的情況更為復(fù)雜了??纯磮D 4-2,然后您會發(fā)現(xiàn)實際上只有三個有關(guān)的類 API,用于執(zhí)行就緒選擇: - 選擇器(Selector)
- 選擇器類管理著一個被注冊的通道集合的信息和它們的就緒狀態(tài)。通道是和選擇器一起被注冊的,并且使用選擇器來更新通道的就緒狀態(tài)。當(dāng)這么做的時候,可以選擇將被激發(fā)的線程掛起,直到有就緒的的通道。
- 可選擇通道(SelectableChannel)
- 這個抽象類提供了實現(xiàn)通道的可選擇性所需要的公共方法。它是所有支持就緒檢查的通道類的父類。
FileChannel對象不是可選擇的,因為它們沒有繼承 SelectableChannel(見圖 4-2)。所有socket通道都是可選擇的,包括從管道(Pipe)對象的中獲得的通道。SelectableChannel可以被注冊到Selector對象上,同時可以指定對那個選擇器而言,那種操作是感興趣的。一個通道可以被注冊到多個選擇器上,但對每個選擇器而言只能被注冊一次。 - 選擇鍵(SelectionKey)
- 選擇鍵封裝了特定的通道與特定的選擇器的注冊關(guān)系。選擇鍵對象被
SelectableChannel.register()返回并提供一個表示這種注冊關(guān)系的標(biāo)記。選擇鍵包含了兩個比特集(以整數(shù)的形式進(jìn)行編碼),指示了該注冊關(guān)系所關(guān)心的通道操作,以及通道已經(jīng)準(zhǔn)備好的操作。
圖 4-1. 就緒選擇相關(guān)類的繼承關(guān)系圖
讓我們看看SelectableChannel的相關(guān)API方法 - public abstract class SelectableChannel extends AbstractChannel implements Channel {
- // 這里僅列出部分API
- public abstract SelectionKey register(Selector sel, int ops) throws ClosedChannelException;
- public abstract SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException;
- public abstract boolean isRegistered();
- public abstract SelectionKey keyFor(Selector sel);
- public abstract int validOps();
- public abstract void configureBlocking (boolean block) throws IOException;
- public abstract boolean isBlocking();
- public abstract Object blockingLock();
- }
非阻塞特性與多元執(zhí)行特性的關(guān)系是十分密切的——以至于java.nio的架構(gòu)將兩者的 API放到了一個類中。 我們已經(jīng)探討了如何用上面列出的SelecableChannel的最后三個方法來配置并檢查通道的阻塞模式(詳細(xì)的探討請參考 3.5.1 小節(jié))。通道在被注冊到一個選擇器上之前,必須先設(shè)置為非阻塞模式(通過調(diào)用configureBlocking(false))。 圖 4-2. 就緒選擇相關(guān)類的關(guān)系
調(diào)用可選擇通道的register()方法會將它注冊到一個選擇器上。如果您試圖注冊一個處于阻塞狀態(tài)的通道,register()將拋出未檢查的IllegalBlockingModeException異常。此外,通道一旦被注冊,就不能回到阻塞狀態(tài)。試圖這么做的話,將在調(diào)用configureBlocking()方法時將拋出IllegalBlockingModeException異常。 并且,理所當(dāng)然地,試圖注冊一個已經(jīng)關(guān)閉的SelectableChannel實例的話,也將拋出ClosedChannelException異常,就像方法原型指示的那樣。 在我們進(jìn)一步了解register()和SelectableChannel的其他方法之前,讓我們先了解一下Selector類的API,以確保我們可以更好地理解這種關(guān)系: - public abstract class Selector {
- public static Selector open() throws IOException
- public abstract boolean isOpen();
- public abstract void close() throws IOException;
- public abstract SelectionProvider provider();
- public abstract int select() throws IOException;
- public abstract int select(long timeout) throws IOException;
- public abstract int selectNow() throws IOException;
- public abstract void wakeup();
- public abstract Set keys();
- public abstract Set selectedKeys();
- }
盡管SelectableChannel類上定義了register()方法,還是應(yīng)該將通道注冊到選擇器上,而不是另一種方式。選擇器維護(hù)了一個需要監(jiān)控的通道的集合。一個給定的通道可以被注冊到多于一個的選擇器上 ,而且不需要知道它被注冊了那個Selector對象上 。將register()放在SelectableChannel上而不是Selector上,這種做法看起來有點隨意。它將返回一個封裝了兩個對象的關(guān)系的選擇鍵對象。重要的是要記住選擇器對象控制了被注冊到它之上的通道的選擇過程。 - 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()
- }
選擇器才是提供管理功能的對象,而不是可選擇通道對象。選擇器對象對注冊到它之上的通道執(zhí)行就緒選擇,并管理選擇鍵。 對于鍵的interest(感興趣的操作)集合和ready(已經(jīng)準(zhǔn)備好的操作)集合的解釋是和特定的通道相關(guān)的。每個通道的實現(xiàn),將定義它自己的選擇鍵類。在register()方法中構(gòu)造它并將它傳遞給所提供的選擇器對象。 在下面的章節(jié)里,我們將了解關(guān)于這三個類的方法的更多細(xì)節(jié)。 Java nio入門教程詳解(三十二)
0
0
我們認(rèn)為:用戶的主要目的,是為了獲取有用的信息,而不是來點擊廣告的。因此本站將竭力做好內(nèi)容,并將廣告和內(nèi)容進(jìn)行分離,確保所有廣告不會影響到用戶的正常閱讀體驗。用戶僅憑個人意愿和興趣愛好點擊廣告。
我們堅信:只有給用戶帶來價值,用戶才會給我們以回報。
|