真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何進(jìn)行JavaNIO的wakeup剖析

如何進(jìn)行Java NIO的wakeup剖析,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。

公司主營(yíng)業(yè)務(wù):成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)公司推出烏蘭免費(fèi)做網(wǎng)站回饋大家。

java NIO的實(shí)現(xiàn)中,有不少細(xì)節(jié)點(diǎn)非常有學(xué)習(xí)意義的,就好比下面的這個(gè)點(diǎn):

Selector的 wakeup原理是什么?是如何實(shí)現(xiàn)的?

wakeup()

準(zhǔn)確來說,應(yīng)該是Selector的wakeup(),即Selector的喚醒,為什么要有這個(gè)喚醒操作呢?那還得從Selector的選擇方式 來說明,前文已經(jīng)總結(jié)過Selector的選擇方式有三種:select()、select(timeout)、selectNow()。
selectNow的選擇過程是非阻塞的,與wakeup沒有太大關(guān)系。

select(timeout)和select()的選擇過程是阻塞的,其他線程如果想終止這個(gè)過程,就可以調(diào)用wakeup來喚醒。

wakeup的原理

既然Selector阻塞式選擇因?yàn)檎业礁信d趣事件ready才會(huì)返回(排除超時(shí)、中斷),就給它構(gòu)造一個(gè)感興趣事件ready的場(chǎng)景即可。下圖可以比較形象的形容wakeup原理:

Selector管轄的FD(文件描述符,linux即為fd,對(duì)應(yīng)一個(gè)文件,windows下對(duì)應(yīng)一個(gè)句柄;每個(gè)可選擇Channel在創(chuàng)建的時(shí) 候,就生成了與其對(duì)應(yīng)的FD,Channel與FD的聯(lián)系見另一篇)中包含某一個(gè)FD A, A對(duì)數(shù)據(jù)可讀事件感興趣,當(dāng)往圖中漏斗端放入(寫入)數(shù)據(jù),數(shù)據(jù)會(huì)流進(jìn)A,于是A有感興趣事件ready,最終,select得到結(jié)果而返回。

wakeup在Selector中的定義如下:

public abstract Selector wakeup();

下面結(jié)合上圖來追尋wakeup的實(shí)現(xiàn):

linux下Selector默認(rèn)實(shí)現(xiàn)為PollSelectorImpl,當(dāng)內(nèi)核版本大于2.6時(shí),實(shí)現(xiàn)為EPollSelectorImpl,僅看這兩者的wakeup方法,代碼似乎完全一樣:

public Selector wakeup() {     synchronized (interruptLock) {         if (!interruptTriggered) {             pollWrapper.interrupt();             interruptTriggered = true;         }     }     return this; }

window下Selector的實(shí)現(xiàn)為WindowsSelectorImpl,其wakeup實(shí)現(xiàn)如下:

public Selector wakeup() {     synchronized (interruptLock) {         if (!interruptTriggered) {             setWakeupSocket();             interruptTriggered = true;         }     }     return this; }

其中interruptTriggered為中斷已觸發(fā)標(biāo)志,當(dāng)pollWrapper.interrupt()之后,該標(biāo)志即為true了;得益于這個(gè)標(biāo)志,連續(xù)兩次wakeup,只會(huì)有一次效果。

對(duì)比上圖及上述代碼,其實(shí)pollWrapper.interrupt()及setWakeupSocket()就是圖中的往漏斗中倒水的過程,不 管windows也好,linux也好,它們wakeup的思想是完全一致的,不同的地方就在于實(shí)現(xiàn)的細(xì)節(jié)了,例如上圖中漏斗與通道的鏈接部 分,linux下是采用管道pipe來實(shí)現(xiàn)的,而windows下是采用兩個(gè)socket之間的通訊來實(shí)現(xiàn)的,它們都有這樣的特性:

1)都有兩個(gè)端,一個(gè) 是read端,一個(gè)是write端,windows中兩個(gè)socket也是一個(gè)扮演read的角色,一個(gè)扮演write的角色;

2)當(dāng)往write端寫入 數(shù)據(jù),則read端即可以收到數(shù)據(jù);從它們的特性可以看出,它們是能夠勝任這份工作的。

如果只想理解wakeup的原理,看到這里應(yīng)該差不多了,不過,下面,想繼續(xù)深入一下,滿足更多人的好奇心。

先看看linux下PollSelector的具體wakeup實(shí)現(xiàn),分階段來介紹:

1)準(zhǔn)備階段

PollSelector在構(gòu)造的時(shí)候,就將管道pipe,及wakeup專用FD給準(zhǔn)備好,可以看一下它的實(shí)現(xiàn):

PollSelectorImpl(SelectorProvider sp) {     super(sp, 1, 1);     int[] fdes = new int[2];     IOUtil.initPipe(fdes, false);     fd0 = fdes[0];     fd1 = fdes[1];     pollWrapper = new PollArrayWrapper(INIT_CAP);     pollWrapper.initInterrupt(fd0, fd1);     channelArray = new SelectionKeyImpl[INIT_CAP]; }

IOUtil.initPipe,采用系統(tǒng)調(diào)用pipe(int fd[2])來創(chuàng)建管道,fd[0]即為ready端,fd[1]即為write端。

另一個(gè)需要關(guān)注的點(diǎn)就是pollWrapper.initInterrupt(fd0, fd1),先看一下它的實(shí)現(xiàn):

void initInterrupt(int fd0, int fd1) {     interruptFD = fd1;     putDescriptor(0, fd0);     putEventOps(0, POLLIN);     putReventOps(0, 0); }

以看到,initInterrupt在準(zhǔn)備wakeup專用FD,因?yàn)閒d0是read端fd,fd1是write端fd:

interruptFD被初始化為write端fd;

putDescriptor(0, fd0)初始化pollfd數(shù)組中的***個(gè)pollfd,即指PollSelector關(guān)注的***個(gè)fd,即為fd0;

putEventOps(0, POLLIN)初始化fd0對(duì)應(yīng)pollfd中的events為POLLIN,即指fd0對(duì)可讀事件感興趣;

putReventOps(0, 0)只是初始化一下fd0對(duì)應(yīng)的pollfd中的revents;

2)執(zhí)行階段

有了前面的準(zhǔn)備工作,就看PollArrayWrapper中的interrupt()實(shí)現(xiàn):

public void interrupt() {     interrupt(interruptFD); }

interrupt是native方法,它的入?yún)nterruptFD即為準(zhǔn)備階段管道的write端fd,對(duì)應(yīng)于上圖,其實(shí)就是漏斗端,因此,就是不看其實(shí)現(xiàn),也知道它肯定扮演著倒水的這個(gè)動(dòng)作,看其實(shí)現(xiàn):

JNIEXPORT void JNICALL Java_sun_nio_ch_PollArrayWrapper_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");     } }

可以看出,interrupt(interruptFD)是往管道的write端fd1中寫入一個(gè)字節(jié)(write(fd, fakebuf, 1))。

是的,只需要往fd1中寫入一個(gè)字節(jié),fd0即滿足了可讀事件ready,則Selector自然會(huì)因?yàn)橛惺录eady而中止阻塞返回。

EPollSelector與PollSelector相比,其wakeup實(shí)現(xiàn)就只有initInterrupt不同,它的實(shí)現(xiàn)如下:

void initInterrupt(int fd0, int fd1) {     outgoingInterruptFD = fd1;     incomingInterruptFD = fd0;     epollCtl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN); }

epfd之前的篇章里已經(jīng)講過,它是通過epoll_create創(chuàng)建出來的epoll文件fd,epollCtl調(diào)用內(nèi)核epoll_ctl實(shí)現(xiàn)了往epfd上添加fd0,且其感興趣事件為可讀(EPOLLIN)。

因此可以斷定,EPollSelector與PollSelector的wakeup實(shí)現(xiàn)是一致的。

因?yàn)橹耙恢睂W⑴c分析linux下的Java NIO實(shí)現(xiàn),忽略了windows下的選擇過程等,這里突然講解其wakeup實(shí)現(xiàn)似乎很突兀,所以打算后面專門起一篇來介紹windows下的NIO實(shí) 現(xiàn),這里我們只需要理解wakeup原理,甚至自己去看看其wakeup實(shí)現(xiàn),應(yīng)該也沒什么難度。

關(guān)于如何進(jìn)行Java NIO的wakeup剖析問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。


網(wǎng)站欄目:如何進(jìn)行JavaNIO的wakeup剖析
文章來源:http://weahome.cn/article/pssheh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部