Java Nio選擇器Selector

Selector

Selector(選擇器)是Java NIO中能夠檢測一到多個(gè)NIO通道,并能夠知曉通道是否為諸如讀寫事件做好準(zhǔn)備的組件。這樣能耻,一個(gè)單獨(dú)的線程可以管理多個(gè)channel亡驰,從而管理多個(gè)網(wǎng)絡(luò)連接 凡辱,減少服務(wù)器的性能開銷。

創(chuàng)建Selector

  • 通過Selector 提供的靜態(tài)方法創(chuàng)建

    Selector selector = Selector.open();
    
  • 通過SelectorProvider獲取選擇器

    SelectorProvider selectorProvider = SelectorProvider.provider();
    Selector selector = selectorProvider.openSelector();
    

將通道注冊到選擇器上

通過ServerSocketChannel.register(Selector sel, int ops)方法注冊的selecor中

//獲取通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//切換到非堵塞模式
serverSocketChannel.configureBlocking(false);
//綁定端口號
serverSocketChannel.bind(new InetSocketAddress(8080));
//獲取選擇器
Selector selector = Selector.open();
//將通道注冊到選擇器上,并且指定“監(jiān)聽接收事件”
SelectionKey key = serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);

與selector使用乳乌,channel必須處于非堵塞狀態(tài)下汉操,F(xiàn)ileChannel無法切換到非堵塞狀態(tài)下將不能與selector一起使用。

register()中的第二個(gè)參數(shù)表示通道監(jiān)聽的事件一共四種狀態(tài)

  • SelectionKey.OP_CONNECT 連接
  • SelectionKey.OP_ACCEPT 接收
  • SelectionKey.OP_READ 讀
  • SelectionKey.OP_WRITE 寫

單一個(gè)通道監(jiān)聽多種事件時(shí)使用位或多種事件如: SelectionKey.OP_CONNECT|SelectionKey.OP_ACCEPT

Selector的select()方法

Selector中注冊了一或多個(gè)通道磷瘤,就可以調(diào)用幾個(gè)重載的select()方法芒篷。這些方法返回通道的事件(如連接、接受采缚、讀或?qū)懀┮呀?jīng)準(zhǔn)備就緒的那些通道针炉。換句話說,如果你對“讀就緒”的通道感興趣仰担,select()方法會返回讀事件已經(jīng)就緒的那些通道糊识。

下面是select()方法:

  • int select()
  • int select(long timeout)
  • int selectNow()

select()阻塞到至少有一個(gè)通道在你注冊的事件上就緒了。

select(long timeout)和select()一樣摔蓝,除了最長會阻塞timeout毫秒(參數(shù))赂苗。

selectNow()不會阻塞,不管什么通道就緒都立刻返回(此方法執(zhí)行非阻塞的選擇操作贮尉。如果自從前一次選擇操作后,沒有通道變成可選擇的猜谚,則此方法直接返回零败砂。)赌渣。

select()方法返回的int值表示有多少通道已經(jīng)就緒。亦即昌犹,自上次調(diào)用select()方法后有多少通道變成就緒狀態(tài)坚芜。如果調(diào)用select()方法,因?yàn)橛幸粋€(gè)通道變成就緒狀態(tài)斜姥,返回了1鸿竖,若再次調(diào)用select()方法,如果另一個(gè)通道就緒了铸敏,它會再次返回1缚忧。如果對第一個(gè)就緒的channel沒有做任何操作,現(xiàn)在就有兩個(gè)就緒的通道杈笔,但在每次select()方法調(diào)用之間闪水,只有一個(gè)通道就緒了。

selectedKeys()

一旦調(diào)用了select()方法蒙具,并且返回值表明有一個(gè)或更多個(gè)通道就緒了球榆,然后可以通過調(diào)用selector的selectedKeys()方法,訪問“選擇降炅俊(已就緒的監(jiān)聽事件)”中的就緒通道芜果。如下所示:

Set selectedKeys = selector.selectedKeys()

使用Selector實(shí)現(xiàn)非堵塞Socket

服務(wù)端

//1.獲取通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//2.切換到非堵塞模式
serverSocketChannel.configureBlocking(false);
//3.綁定端口號
serverSocketChannel.bind(new InetSocketAddress(8080));
//4.獲取選擇器
Selector selector = Selector.open();
//5.將通道注冊到選擇器上,并且指定“監(jiān)聽接收事件”
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
//6輪詢式的獲取選擇器上已經(jīng)‘準(zhǔn)備就緒’的事件
while (selector.select()>0){
    //7 融师。獲取當(dāng)前選擇器中所有注冊的"選擇接壹亍(已就緒的監(jiān)聽事件)"
    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
    while (iterator.hasNext()){
        //8.獲取“準(zhǔn)備就緒”的事件
        SelectionKey selectionKey = iterator.next();
         //9.判斷具體事件,就緒
        if (selectionKey.isAcceptable()){
            //10.接收就緒旱爆,獲取客戶端連接
            SocketChannel socketChannel = serverSocketChannel.accept();
            //11,切換到非堵塞模式
            socketChannel.configureBlocking(false);
            //12.將客戶端通道注冊到選擇器上
            socketChannel.register(selector,SelectionKey.OP_READ);
        }else if (selectionKey.isReadable()){
            //獲取當(dāng)前選擇器上“讀就緒”狀態(tài)的通道
            SocketChannel socketChannel = (SocketChannel) selectionKey.channel();

            ByteBuffer buffer = ByteBuffer.allocate(1024);
            //讀取客戶端傳過來的數(shù)據(jù)
            int len = 0;
            while ((len = socketChannel.read(buffer))>0){
              buffer.flip();
              System.out.println(new String(buffer.array(),0,len));
              buffer.clear();  
          }
        }
        //取消選擇鍵selectionKey
        iterator.remove();
    }
}

客戶端

//1.獲取通道
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",8080));
//2.設(shè)置為非堵塞模式
socketChannel.configureBlocking(false);
ByteBuffer buf = ByteBuffer.allocate(1024);
//3.發(fā)送數(shù)據(jù)給服務(wù)端
//控制臺輸入數(shù)據(jù)
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()){
    String msg = scanner.next();
    buf.put(msg.getBytes());
    buf.flip();
    socketChannel.write(buf);
    buf.clear();
}
//4.關(guān)閉連接
socketChannel.close();

更多示例代碼

本文參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舀射,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子怀伦,更是在濱河造成了極大的恐慌脆烟,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件房待,死亡現(xiàn)場離奇詭異邢羔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)桑孩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門拜鹤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人流椒,你說我怎么就攤上這事敏簿。” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵惯裕,是天一觀的道長温数。 經(jīng)常有香客問我,道長蜻势,這世上最難降的妖魔是什么撑刺? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮握玛,結(jié)果婚禮上猜煮,老公的妹妹穿的比我還像新娘。我一直安慰自己败许,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布淑蔚。 她就那樣靜靜地躺著市殷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪刹衫。 梳的紋絲不亂的頭發(fā)上醋寝,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機(jī)與錄音带迟,去河邊找鬼音羞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛仓犬,可吹牛的內(nèi)容都是我干的嗅绰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼搀继,長吁一口氣:“原來是場噩夢啊……” “哼窘面!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起叽躯,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤财边,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后点骑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酣难,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年黑滴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了憨募。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡跷跪,死狀恐怖馋嗜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吵瞻,我是刑警寧澤葛菇,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布甘磨,位于F島的核電站,受9級特大地震影響眯停,放射性物質(zhì)發(fā)生泄漏济舆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一莺债、第九天 我趴在偏房一處隱蔽的房頂上張望滋觉。 院中可真熱鬧,春花似錦齐邦、人聲如沸椎侠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽我纪。三九已至,卻和暖如春丐吓,著一層夾襖步出監(jiān)牢的瞬間浅悉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工券犁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留术健,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓粘衬,卻偏偏與公主長得像荞估,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子稚新,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容

  • # Java NIO # Java NIO屬于非阻塞IO泼舱,這是與傳統(tǒng)IO最本質(zhì)的區(qū)別。傳統(tǒng)IO包括socket和文...
    Teddy_b閱讀 595評論 0 0
  • Java NIO(New IO)是從Java 1.4版本開始引入的一個(gè)新的IO API枷莉,可以替代標(biāo)準(zhǔn)的Java I...
    JackChen1024閱讀 7,555評論 1 143
  • Java NIO(New IO)是從Java 1.4版本開始引入的一個(gè)新的IO API娇昙,可以替代標(biāo)準(zhǔn)的Java I...
    編碼前線閱讀 2,268評論 0 5
  • 參考:http://ifeve.com/selectors/原文地址 目錄 Java NIO教程 Java NIO...
    步積閱讀 4,483評論 3 10
  • 玻璃,雖晶瑩剔透笤妙,卻易碎易破冒掌。如果一個(gè)人不幸長了一顆玻璃心,折射到性格上蹲盘,就是敏感股毫、脆弱,受不得一絲一毫的打擊和挫...
    明哥明說閱讀 735評論 3 1