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