<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢(mèng)蝶

    生活、程序、未來(lái)
       :: 首頁(yè) ::  ::  :: 聚合  :: 管理

    Selector.wakeup實(shí)現(xiàn)注記

    Posted on 2010-10-22 10:35 dennis 閱讀(6228) 評(píng)論(3)  編輯  收藏 所屬分類: java源碼解讀

        NIO中的Selector封裝了底層的系統(tǒng)調(diào)用,其中wakeup用于喚醒阻塞在select方法上的線程,它的實(shí)現(xiàn)很簡(jiǎn)單,在linux上就是創(chuàng)建一個(gè)管道并加入poll的fd集合,wakeup就是往管道里寫一個(gè)字節(jié),那么阻塞的poll方法有數(shù)據(jù)可讀就立即返回。證明這一點(diǎn)很簡(jiǎn)單,strace即可知道:
    public class SelectorTest {
        
    public static void main(String[] args) throws Exception {
            Selector selector 
    = Selector.open();
            selector.wakeup();
        }
    }

         使用strace調(diào)用,只關(guān)心write的系統(tǒng)調(diào)用
    sudo strace --e write java SelectorTest

         輸出:
    Process 29181 attached
    Process 
    29182 attached
    Process 
    29183 attached
    Process 
    29184 attached
    Process 
    29185 attached
    Process 
    29186 attached
    Process 
    29187 attached
    Process 
    29188 attached
    Process 
    29189 attached
    Process 
    29190 attached
    Process 
    29191 attached
    [pid 
    29181] write(36"\1"1)          = 1
    Process 
    29191 detached
    Process 
    29184 detached
    Process 
    29181 detached

        有的同學(xué)說(shuō)了,怎么證明這個(gè)write是wakeup方法調(diào)用的,而不是其他方法呢,這個(gè)很好證明,我們多調(diào)用幾次:
    public class SelectorTest {
        
    public static void main(String[] args) throws Exception {
            Selector selector 
    = Selector.open();
            selector.wakeup();
            selector.selectNow();
            selector.wakeup();
            selector.selectNow();
            selector.wakeup();
        }
    }

        修改程序調(diào)用三次wakeup,心細(xì)的朋友肯定注意到我們還調(diào)用了兩次selectNow,這是因?yàn)樵趦纱纬晒Φ膕elect方法之間調(diào)用wakeup多次都只算做一次,為了顯示3次write,這里就每次調(diào)用前select一下將前一次寫入的字節(jié)讀到,同樣執(zhí)行上面的strace調(diào)用,輸出:

    Process 29303 attached
    Process 
    29304 attached
    Process 
    29305 attached
    Process 
    29306 attached
    Process 
    29307 attached
    Process 
    29308 attached
    Process 
    29309 attached
    Process 
    29310 attached
    Process 
    29311 attached
    Process 
    29312 attached
    Process 
    29313 attached
    [pid 
    29303] write(36"\1"1)          = 1
    [pid 
    29303] write(36"\1"1)          = 1
    [pid 
    29303] write(36"\1"1)          = 1
    Process 
    29313 detached
    Process 
    29309 detached
    Process 
    29306 detached
    Process 
    29303 detached

         果然是3次write的系統(tǒng)調(diào)用,都是寫入一個(gè)字節(jié),如果我們?nèi)サ魋electNow,那么三次wakeup還是等于一次:
    public class SelectorTest {
        
    public static void main(String[] args) throws Exception {
            Selector selector 
    = Selector.open();
            selector.wakeup();
            selector.wakeup();
            selector.wakeup();
        }
    }
     
       輸出:
    Process 29331 attached
    Process 
    29332 attached
    Process 
    29333 attached
    Process 
    29334 attached
    Process 
    29335 attached
    Process 
    29336 attached
    Process 
    29337 attached
    Process 
    29338 attached
    Process 
    29339 attached
    Process 
    29340 attached
    Process 
    29341 attached
    [pid 
    29331] write(36"\1"1)          = 1
    Process 
    29341 detached
    Process 
    29337 detached
    Process 
    29334 detached
    Process 
    29331 detached

          wakeup方法的API說(shuō)明沒有欺騙我們。wakeup方法的API還告訴我們,如果當(dāng)前Selector沒有阻塞在select方法上,那么本次wakeup調(diào)用會(huì)在下一次select阻塞的時(shí)候生效,這個(gè)道理很簡(jiǎn)單,wakeup方法寫入一個(gè)字節(jié),下次poll等待的時(shí)候立即發(fā)現(xiàn)可讀并返回,因此不會(huì)阻塞。

         具體到源碼級(jí)別,在linux平臺(tái)上的wakeup方法其實(shí)調(diào)用了pipe創(chuàng)建了管道,wakeup調(diào)用了EPollArrayWrapperinterrupt方法:
    public  void interrupt() 

    {
            interrupt(outgoingInterruptFD);
    }

        實(shí)際調(diào)用的是interrupt(fd)的native方法,查看EPollArrayWrapper.c可見清晰的write系統(tǒng)調(diào)用:

    JNIEXPORT 
    void JNICALL
    Java_sun_nio_ch_EPollArrayWrapper_interrupt(JNIEnv 
    *env, jobject this, jint fd)
    {
        
    int fakebuf[1];
        fakebuf[
    0= 1;
        
    if (write(fd, fakebuf, 1< 0) {
            JNU_ThrowIOExceptionWithLastError(env,
    "write to interrupt fd failed");
        }
    }
        寫入一個(gè)字節(jié)的fakebuf。有朋友問(wèn)起這個(gè)問(wèn)題,寫個(gè)注記在此。strace充分利用對(duì)了解這些細(xì)節(jié)很有幫助。
     


    評(píng)論

    # re: Selector.wakeup實(shí)現(xiàn)注記  回復(fù)  更多評(píng)論   

    2010-10-22 11:01 by BucketLI
    好像在網(wǎng)絡(luò)IO中很有用的一個(gè)命令,記下了。
    然后能否多分享一些其他有用的網(wǎng)絡(luò)命令?

    # re: Selector.wakeup實(shí)現(xiàn)注記  回復(fù)  更多評(píng)論   

    2010-10-22 22:19 by 上情下愛
    不錯(cuò),謝謝~
    欣賞博主的鉆研和分享精神

    # re: Selector.wakeup實(shí)現(xiàn)注記  回復(fù)  更多評(píng)論   

    2011-05-09 21:56 by niumd
    讀了mina、netty的源碼,但是在閱讀您的文章后受益匪淺,覺得自己理解還不夠深入,希望那個(gè)樓主在多處精彩文章;謝謝分享。
    主站蜘蛛池模板: 亚洲av永久无码精品网址| 亚洲另类小说图片| 国产99久久久国产精免费| 亚洲欧洲日产国码高潮αv| 国产午夜亚洲精品不卡免下载| 成人免费无码精品国产电影| 亚洲欧洲无码AV不卡在线 | 99国产精品免费观看视频| 亚洲AV无码不卡无码| 在线看无码的免费网站| 精品亚洲成A人无码成A在线观看| 69天堂人成无码麻豆免费视频| 亚洲综合偷自成人网第页色| 白白国产永久免费视频| 免费视频精品一区二区| 亚洲精品美女久久久久99| 日韩插啊免费视频在线观看| 亚洲一级毛片在线播放| 国产一级高清视频免费看| 久久久久免费视频| 噜噜噜亚洲色成人网站∨| 成人性生免费视频| caoporn国产精品免费| 久久夜色精品国产亚洲AV动态图| 国产成人精品久久免费动漫| 亚洲AV成人精品日韩一区| 久久精品国产亚洲7777| 青青草原1769久久免费播放 | 亚洲国产成人无码AV在线影院| 亚洲成a人片在线观看国产| 九九美女网站免费| 亚洲愉拍一区二区三区| 狠狠亚洲狠狠欧洲2019| 亚洲免费电影网站| 九九免费精品视频在这里| 亚洲国产天堂久久综合网站| 日本久久久免费高清| 青青草原1769久久免费播放| 亚洲成av人在线观看网站| 久久亚洲一区二区| 国产乱人免费视频|