日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Java nio入門教程詳解(0034)

 360lec 2016-09-30

4.3 使用選擇器

既然我們已經(jīng)很好地掌握了各種不同類以及它們之間的關(guān)聯(lián),那么現(xiàn)在讓我們進(jìn)一步了解Selector類,也就是就緒選擇的核心。這里是Selector類的可用的 API。在 4.1.2 小節(jié)中,我們已經(jīng)看到如何創(chuàng)建新的選擇器,那么那些方法還剩下:

4.3.1 選擇過程

在詳細(xì)了解API之前,您需要知道一點(diǎn)和Selector內(nèi)部工作原理相關(guān)的知識(shí)。就像上面探討的那樣,選擇器維護(hù)著注冊過的通道的集合,并且這些注冊關(guān)系中的任意一個(gè)都是封裝在SelectionKey對(duì)象中的。每一個(gè)Selector對(duì)象維護(hù)三個(gè)鍵的集合:

  1. public abstract class Selector {
  2.     // 這里僅列出部分API
  3.     public abstract Set keys();
  4.     public abstract Set selectedKeys();
  5.     public abstract int select() throws IOException;
  6.     public abstract int select (long timeout) throws IOException;
  7.     public abstract int selectNow() throws IOException;
  8.     public abstract void wakeup();
  9. }
已注冊的鍵的集合(Registered key set)
與選擇器關(guān)聯(lián)的已經(jīng)注冊的鍵的集合。并不是所有注冊過的鍵都仍然有效。這個(gè)集合通過keys()方法返回,并且可能是空的。這個(gè)已注冊的鍵的集合不是可以直接修改的;試圖這么做的話將引發(fā)java.lang.UnsupportedOperationException。
已選擇的鍵的集合(Selected key set)
已注冊的鍵的集合的子集。這個(gè)集合的每個(gè)成員都是相關(guān)的通道被選擇器(在前一個(gè)選擇操作中)判斷為已經(jīng)準(zhǔn)備好的,并且包含于鍵的interest集合中的操作。這個(gè)集合通過selectedKeys()方法返回(并有可能是空的)。

不要將已選擇的鍵的集合與ready集合弄混了。這是一個(gè)鍵的集合,每個(gè)鍵都關(guān)聯(lián)一個(gè)已經(jīng)準(zhǔn)備好至少一種操作的通道。每個(gè)鍵都有一個(gè)內(nèi)嵌的ready集合,指示了所關(guān)聯(lián)的通道已經(jīng)準(zhǔn)備好的操作。

鍵可以直接從這個(gè)集合中移除,但不能添加。試圖向已選擇的鍵的集合中添加元素將拋出java.lang.UnsupportedOperationException。

已取消的鍵的集合(Cancelled key set)
已注冊的鍵的集合的子集,這個(gè)集合包含了cancel()方法被調(diào)用過的鍵(這個(gè)鍵已經(jīng)被無效化),但它們還沒有被注銷。這個(gè)集合是選擇器對(duì)象的私有成員,因而無法直接訪問。

在一個(gè)剛初始化的Selector對(duì)象中,這三個(gè)集合都是空的。

Selector類的核心是選擇過程。這個(gè)名詞您已經(jīng)在之前看過多次了——現(xiàn)在應(yīng)該解釋一下了?;旧蟻碚f,選擇器是對(duì)select()、poll()等本地調(diào)用(native call)或者類似的操作系統(tǒng)特定的系統(tǒng)調(diào)用的一個(gè)包裝。但是Selector所作的不僅僅是簡單地向本地代碼傳送參數(shù)。它對(duì)每個(gè)選擇操作應(yīng)用了特定的過程。對(duì)這個(gè)過程的理解是合理地管理鍵和它們所表示的狀態(tài)信息的基礎(chǔ)。

選擇操作是當(dāng)三種形式的select()中的任意一種被調(diào)用時(shí),由選擇器執(zhí)行的。不管是哪一種形式的調(diào)用,下面步驟將被執(zhí)行:

    • 已取消的鍵的集合將會(huì)被檢查。如果它是非空的,每個(gè)已取消的鍵的集合中的鍵將從另外兩個(gè)集合中移除,并且相關(guān)的通道將被注銷。這個(gè)步驟結(jié)束后,已取消的鍵的集合將是空的。
    • 已注冊的鍵的集合中的鍵的interest集合將被檢查。在這個(gè)步驟中的檢查執(zhí)行過后,對(duì)interest集合的改動(dòng)不會(huì)影響剩余的檢查過程。

      一旦就緒條件被定下來,底層操作系統(tǒng)將會(huì)進(jìn)行查詢,以確定每個(gè)通道所關(guān)心的操作的真實(shí)就緒狀態(tài)。依賴于特定的select()方法調(diào)用,如果沒有通道已經(jīng)準(zhǔn)備好,線程可能會(huì)在這時(shí)阻塞,通常會(huì)有一個(gè)超時(shí)值。

      直到系統(tǒng)調(diào)用完成為止,這個(gè)過程可能會(huì)使得調(diào)用線程睡眠一段時(shí)間,然后當(dāng)前每個(gè)通道的就緒狀態(tài)將確定下來。對(duì)于那些還沒準(zhǔn)備好的通道將不會(huì)執(zhí)行任何的操作。對(duì)于那些操作系統(tǒng)指示至少已經(jīng)準(zhǔn)備好interest集合中的一種操作的通道,將執(zhí)行以下兩種操作中的一種:

      a.如果通道的鍵還沒有處于已選擇的鍵的集合中,那么鍵的ready集合將被清空,然后表示操作系統(tǒng)發(fā)現(xiàn)的當(dāng)前通道已經(jīng)準(zhǔn)備好的操作的比特掩碼將被設(shè)置。

      b.否則,也就是鍵在已選擇的鍵的集合中。鍵的ready集合將被表示操作系統(tǒng)發(fā)現(xiàn)的當(dāng)前已經(jīng)準(zhǔn)備好的操作的比特掩碼更新。所有之前的已經(jīng)不再是就緒狀態(tài)的操作不會(huì)被清除。事實(shí)上,所有的比特位都不會(huì)被清理。由操作系統(tǒng)決定的ready集合是與之前的ready集合按位分離的,一旦鍵被放置于選擇器的已選擇的鍵的集合中,它的ready集合將是累積的。比特位只會(huì)被設(shè)置,不會(huì)被清理。

    • 步驟2可能會(huì)花費(fèi)很長時(shí)間,特別是所激發(fā)的線程處于休眠狀態(tài)時(shí)。與該選擇器相關(guān)的鍵可能會(huì)同時(shí)被取消。當(dāng)步驟2結(jié)束時(shí),步驟1將重新執(zhí)行,以完成任意一個(gè)在選擇進(jìn)行的過程中,鍵已經(jīng)被取消的通道的注銷。
    • select操作返回的值是ready集合在步驟2中被修改的鍵的數(shù)量,而不是已選擇的鍵的集合中的通道的總數(shù)。返回值不是已準(zhǔn)備好的通道的總數(shù),而是從上一個(gè)select()調(diào)用之后進(jìn)入就緒狀態(tài)的通道的數(shù)量。之前的調(diào)用中就緒的,并且在本次調(diào)用中仍然就緒的通道不會(huì)被計(jì)入,而那些在前一次調(diào)用中已經(jīng)就緒但已經(jīng)不再處于就緒狀態(tài)的通道也不會(huì)被計(jì)入。這些通道可能仍然在已選擇的鍵的集合中,但不會(huì)被計(jì)入返回值中。返回值可能是0。

      使用內(nèi)部的已取消的鍵的集合來延遲注銷,是一種防止線程在取消鍵時(shí)阻塞,并防止與正在進(jìn)行的選擇操作沖突的優(yōu)化。注銷通道是一個(gè)潛在的代價(jià)很高的操作,這可能需要重新分配資源(請(qǐng)記住,鍵是與通道相關(guān)的,并且可能與它們相關(guān)的通道對(duì)象之間有復(fù)雜的交互)。清理已取消的鍵,并在選擇操作之前和之后立即注銷通道,可以消除它們可能正好在選擇的過程中執(zhí)行的潛在棘手問題。這是另一個(gè)兼顧健壯性的折中方案。

    • Selector類的select()方法有以下三種不同的形式:

      這三種select的形式,僅僅在它們在所注冊的通道當(dāng)前都沒有就緒時(shí),是否阻塞的方面有所不同。最簡單的沒有參數(shù)的形式可以用如下方式調(diào)用:

      public abstract int select() throws IOException;

      這種調(diào)用在沒有通道就緒時(shí)將無限阻塞。一旦至少有一個(gè)已注冊的通道就緒,選擇器的選擇鍵就會(huì)被更新,并且每個(gè)就緒的通道的ready集合也將被更新。返回值將會(huì)是已經(jīng)確定就緒的通道的數(shù)目。正常情況下,這些方法將返回一個(gè)非零的值,因?yàn)橹钡揭粋€(gè)通道就緒前它都會(huì)阻塞。但是它也可以返回非0值,如果選擇器的wakeup()方法被其他線程調(diào)用。

      有時(shí)您會(huì)想要限制線程等待通道就緒的時(shí)間。這種情況下,可以使用一個(gè)接受一個(gè)超時(shí)參數(shù)的select()方法的重載形式:

      public abstract int select(long timeout) throws IOException;

      這種調(diào)用與之前的例子完全相同,除了如果在您提供的超時(shí)時(shí)間(以毫秒計(jì)算)內(nèi)沒有通道就緒時(shí),它將返回0。如果一個(gè)或者多個(gè)通道在時(shí)間限制終止前就緒,鍵的狀態(tài)將會(huì)被更新,并且方法會(huì)在那時(shí)立即返回。將超時(shí)參數(shù)指定為0表示將無限期等待,那么它就在各個(gè)方面都等同于使用無參數(shù)版本的select()了。

      就緒選擇的第三種也是最后一種形式是完全非阻塞的:

      int n = selector.selectNow();

      selectNow()方法執(zhí)行就緒檢查過程,但不阻塞。如果當(dāng)前沒有通道就緒,它將立即返回0。

      Java nio入門教程詳解(三十五)

      本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
      轉(zhuǎn)藏 分享 獻(xiàn)花(0

      0條評(píng)論

      發(fā)表

      請(qǐng)遵守用戶 評(píng)論公約

      類似文章 更多