生活随笔
收集整理的這篇文章主要介紹了
tomcat架构分析 (connector NIO 实现)【转】
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
原文地址:https://www.iteye.com/blog/gearever-1844203
ller線程中維護(hù)的這個Selector標(biāo)為主Selector。?
Poller是NIO實(shí)現(xiàn)的主要線程。首先作為events queue的消費(fèi)者,從queue中取出PollerEvent對象,然后將此對象中的channel以O(shè)P_READ事件注冊到主Selector中,然后主Selector執(zhí)行select操作,遍歷出可以讀數(shù)據(jù)的socket,并從Worker線程池中拿到可用的Worker線程,然后將socket傳遞給Worker。整個過程是典型的NIO實(shí)現(xiàn)。?
Worker?
Worker線程拿到Poller傳過來的socket后,將socket封裝在SocketProcessor對象中。然后從Http11ConnectionHandler中取出Http11NioProcessor對象,從Http11NioProcessor中調(diào)用CoyoteAdapter的邏輯,跟BIO實(shí)現(xiàn)一樣。在Worker線程中,會完成從socket中讀取http request,解析成HttpServletRequest對象,分派到相應(yīng)的servlet并完成邏輯,然后將response通過socket發(fā)回client。在從socket中讀數(shù)據(jù)和往socket中寫數(shù)據(jù)的過程,并沒有像典型的非阻塞的NIO的那樣,注冊O(shè)P_READ或OP_WRITE事件到主Selector,而是直接通過socket完成讀寫,這時是阻塞完成的,但是在timeout控制上,使用了NIO的Selector機(jī)制,但是這個Selector并不是Poller線程維護(hù)的主Selector,而是BlockPoller線程中維護(hù)的Selector,稱之為輔Selector。?
NioSelectorPool?
NioEndpoint對象中維護(hù)了一個NioSelecPool對象,這個NioSelectorPool中又維護(hù)了一個BlockPoller線程,這個線程就是基于輔Selector進(jìn)行NIO的邏輯。以執(zhí)行servlet后,得到response,往socket中寫數(shù)據(jù)為例,最終寫的過程調(diào)用NioBlockingSelector的write方法。?
Java代碼??
public?int?write(ByteBuffer?buf,?NioChannel?socket,?long?writeTimeout,MutableInteger?lastWrite)?throws?IOException?{??????????SelectionKey?key?=?socket.getIOChannel().keyFor(socket.getPoller().getSelector());??????????if?(?key?==?null?)?throw?new?IOException("Key?no?longer?registered");??????????KeyAttachment?att?=?(KeyAttachment)?key.attachment();??????????int?written?=?0;??????????boolean?timedout?=?false;??????????int?keycount?=?1;?????????long?time?=?System.currentTimeMillis();?????????try?{??????????????while?(?(!timedout)?&&?buf.hasRemaining())?{??????????????????if?(keycount?>?0)?{?????????????????????????????????????????int?cnt?=?socket.write(buf);?????????????????????lastWrite.set(cnt);??????????????????????if?(cnt?==?-1)??????????????????????????throw?new?EOFException();??????????????????????written?+=?cnt;??????????????????????????????????????????if?(cnt?>?0)?{??????????????????????????time?=?System.currentTimeMillis();?????????????????????????continue;?????????????????????}??????????????????}??????????????????????????????????try?{??????????????????????????????????????????if?(?att.getWriteLatch()==null?||?att.getWriteLatch().getCount()==0)?att.startWriteLatch(1);??????????????????????????????????????????poller.add(att,SelectionKey.OP_WRITE);??????????????????????????????????????????att.awaitWriteLatch(writeTimeout,TimeUnit.MILLISECONDS);??????????????????}catch?(InterruptedException?ignore)?{??????????????????????Thread.interrupted();??????????????????}??????????????????if?(?att.getWriteLatch()!=null?&&?att.getWriteLatch().getCount()>?0)?{??????????????????????keycount?=?0;??????????????????}else?{??????????????????????????????????????????keycount?=?1;??????????????????????att.resetWriteLatch();??????????????????}????????????????????if?(writeTimeout?>?0?&&?(keycount?==?0))??????????????????????timedout?=?(System.currentTimeMillis()?-?time)?>=?writeTimeout;??????????????}?????????????if?(timedout)???????????????????throw?new?SocketTimeoutException();??????????}?finally?{??????????????poller.remove(att,SelectionKey.OP_WRITE);??????????????if?(timedout?&&?key?!=?null)?{??????????????????poller.cancelKey(socket,?key);??????????????}??????????}??????????return?written;??????}??
也就是說當(dāng)socket.write()返回0時,說明網(wǎng)絡(luò)狀態(tài)不穩(wěn)定,這時將socket注冊O(shè)P_WRITE事件到輔Selector,由BlockPoller線程不斷輪詢這個輔Selector,直到發(fā)現(xiàn)這個socket的寫狀態(tài)恢復(fù)了,通過那個倒數(shù)計(jì)數(shù)器,通知Worker線程繼續(xù)寫socket動作。看一下BlockSelector線程的邏輯;?
Java代碼??
public?void?run()?{??????????????while?(run)?{??????????????????try?{??????????????????????......????????????????????????Iterator?iterator?=?keyCount?>?0???selector.selectedKeys().iterator()?:?null;??????????????????????while?(run?&&?iterator?!=?null?&&?iterator.hasNext())?{??????????????????????????SelectionKey?sk?=?(SelectionKey)?iterator.next();??????????????????????????KeyAttachment?attachment?=?(KeyAttachment)sk.attachment();??????????????????????????try?{??????????????????????????????attachment.access();??????????????????????????????iterator.remove();?;??????????????????????????????sk.interestOps(sk.interestOps()?&?(~sk.readyOps()));??????????????????????????????if?(?sk.isReadable()?)?{??????????????????????????????????countDown(attachment.getReadLatch());??????????????????????????????}??????????????????????????????????????????????????????????if?(sk.isWritable())?{??????????????????????????????????countDown(attachment.getWriteLatch());??????????????????????????????}??????????????????????????}catch?(CancelledKeyException?ckx)?{??????????????????????????????if?(sk!=null)?sk.cancel();??????????????????????????????countDown(attachment.getReadLatch());??????????????????????????????countDown(attachment.getWriteLatch());??????????????????????????}??????????????????????}????????????????}catch?(?Throwable?t?)?{??????????????????????log.error("",t);??????????????????}??????????????}??????????????events.clear();??????????????try?{??????????????????selector.selectNow();????????????}catch(?Exception?ignore?)?{??????????????????if?(log.isDebugEnabled())log.debug("",ignore);??????????????}??????????}??
使用這個輔Selector主要是減少線程間的切換,同時還可減輕主Selector的負(fù)擔(dān)。以上描述了NIO connector工作的主要邏輯,可以看到在設(shè)計(jì)上還是比較精巧的。NIO connector還有一塊就是Comet,有時間再說吧。需要注意的是,上面從Acceptor開始,有很多對象的封裝,NioChannel及其KeyAttachment,PollerEvent和SocketProcessor對象,這些不是每次都重新生成一個新的,都是NioEndpoint分別維護(hù)了它們的對象池;?
Java代碼??
ConcurrentLinkedQueue<SocketProcessor>?processorCache?=?new?ConcurrentLinkedQueue<SocketProcessor>()??ConcurrentLinkedQueue<KeyAttachment>?keyCache?=?new?ConcurrentLinkedQueue<KeyAttachment>()??ConcurrentLinkedQueue<PollerEvent>?eventCache?=?new?ConcurrentLinkedQueue<PollerEvent>()??ConcurrentLinkedQueue<NioChannel>?nioChannels?=?new?ConcurrentLinkedQueue<NioChannel>()??
當(dāng)需要這些對象時,分別從它們的對象池獲取,當(dāng)用完后返回給相應(yīng)的對象池,這樣可以減少因?yàn)閯?chuàng)建及GC對象時的性能消耗。
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/articles/11452705.html
總結(jié)
以上是生活随笔為你收集整理的tomcat架构分析 (connector NIO 实现)【转】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。