版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、JavaNIO類庫(kù)Selector機(jī)制解析、八、前言自從J2SE1.4版本以來(lái),JDK發(fā)布了全新的I/O類庫(kù),簡(jiǎn)稱NIO,其不但引入了全新的高效的I/O機(jī)制,同時(shí),也引入了多路復(fù)用的異步模式。NIO的包中主要包含了這樣幾種抽象數(shù)據(jù)類型:Buffer:包含數(shù)據(jù)且用于讀寫的線形表結(jié)構(gòu)。其中還提供了一個(gè)特殊類用于內(nèi)存映射文件的I/O操作。Charset:它提供Unicode字符串影射到字節(jié)序列以及逆映射的操作。Channels:包含socket,file和pipe三種管道,都是全雙工的通道。Selector:多個(gè)異步I/O操作集中到一個(gè)或多個(gè)線程中(可以被看成是Unix中select()函數(shù)的面向?qū)?/p>
2、象版本)。我的大學(xué)同學(xué)趙錕在使用NIO類庫(kù)書寫相關(guān)網(wǎng)絡(luò)程序的時(shí)候,發(fā)現(xiàn)了一些Java異常RuntimeException,異常的報(bào)錯(cuò)信息讓他開始了對(duì)NIO的Selector進(jìn)行了一些調(diào)查。當(dāng)趙錕對(duì)我共享了Selector的一些底層機(jī)制的猜想和調(diào)查時(shí)候,我們覺(jué)得這是一件很有意思的事情,于是在伙同趙錕進(jìn)行過(guò)一系列的調(diào)查后,我倆發(fā)現(xiàn)了很多有趣的事情,于是導(dǎo)致了這篇文章的產(chǎn)生。這也是為什么本文的作者署名為我們兩人的原因。先要說(shuō)明的一點(diǎn)是,趙錕和我本質(zhì)上都是出身于Unix/Linux/C/C+的開發(fā)人員,對(duì)于Java,這并不是我們的長(zhǎng)處,這篇文章本質(zhì)上出于對(duì)Java的Selector的好奇,因?yàn)閺谋砻嫔?/p>
3、來(lái)看Selector似乎做到了一些讓我們這些C/C+出身的人比較驚奇的事情。面讓我來(lái)為你講述一下這段故事。、故事開始:讓C+程序員寫Java程序!沒(méi)有嚴(yán)重內(nèi)存問(wèn)題,大量豐富的SDK類庫(kù),超容易的跨平臺(tái),除了在性能上有些微辭,C+出身的程序員從來(lái)都不會(huì)覺(jué)得Java是一件很困難的事情。當(dāng)然,對(duì)于長(zhǎng)期習(xí)慣于使用操作系統(tǒng)API(系統(tǒng)調(diào)用SystemCall)的C/C+程序來(lái)說(shuō),面對(duì)Java中的比較“另類”地操作系統(tǒng)資源的方法可能會(huì)略感困惑,但萬(wàn)變不離其宗,只需要對(duì)面向?qū)ο蟮脑O(shè)計(jì)模式有一定的了解,用不了多長(zhǎng)時(shí)間,Java的SDK類庫(kù)也能玩得隨心所欲。在使用Java進(jìn)行相關(guān)網(wǎng)絡(luò)程序的的設(shè)計(jì)時(shí),出身C/C+
4、的人,首先想到的框架就是多路復(fù)用,想到多路復(fù)用,Unix/Linux下馬上就能讓從想到select,poll,epoll系統(tǒng)調(diào)用。于是,在看到Java的NIO中的Selector類時(shí)必然會(huì)倍感親切。稍加查閱一下SDK手冊(cè)以及相關(guān)例程,不一會(huì)兒,一個(gè)多路復(fù)用的框架便呈現(xiàn)出來(lái),隨手做個(gè)單元測(cè)試,沒(méi)啥問(wèn)題,一切和C/C+照舊。然后告訴兄弟們,框架搞定,以后咱們就在Windows上開發(fā)及單元測(cè)試,完成后到運(yùn)行環(huán)境Unix上集成測(cè)試。心中并暗自念到,跨平臺(tái)就好啊,開發(fā)活動(dòng)都可以跨平臺(tái)了。然而,好景不長(zhǎng),隨著代碼越來(lái)越多,邏輯越來(lái)越復(fù)雜。好好的框架居然在Windows上單元測(cè)試運(yùn)行開始出現(xiàn)異常,看著Jav
5、a運(yùn)行異常出錯(cuò)的函數(shù)棧,異常居然由Selector.open()拋出,錯(cuò)誤信息居然是Unabletoestablishloopbackconnection?!癝elector.open()居然報(bào)loopbackconnection錯(cuò)誤,憑什么?不應(yīng)該?。縪pen的時(shí)候又沒(méi)有什么loopback的socket連接,怎么會(huì)報(bào)這個(gè)錯(cuò)?”長(zhǎng)期使用C/C+的程序當(dāng)然會(huì)對(duì)操作系統(tǒng)的調(diào)用非常熟悉,雖然Java的虛擬機(jī)搞的什么系統(tǒng)調(diào)用都不見了,但C/C+的程序員必然要比Java程序敏感許多。三、開始調(diào)查:怎么Java這么“傻”!于是,C/C+的老鳥從Systemlnternals上下載ProcessExplo
6、rer來(lái)查看一下究竟是什么個(gè)LoopbackConnectiono果然,打開java運(yùn)行進(jìn)程,發(fā)現(xiàn)有一些自己連接自己的localhost的TCP/IP鏈接。于是另一個(gè)問(wèn)題又出現(xiàn)了,“憑什么?。繛槭裁磿?huì)有自己和自己的連接?我程序里沒(méi)有自己連接自己啊,怎么可能會(huì)有這樣的鏈接啊?而自己連接自己的端口號(hào)居然是些奇怪的端口?!眴?wèn)題變得越來(lái)越蹊蹺了。難道這都是Selector.open()在做怪?難道Selector.open()要?jiǎng)?chuàng)建一個(gè)自己連接自己的鏈接?寫個(gè)程序看看:importjava.nio.channels.Selector;importjava.lang.RuntimeException;i
7、mportjava.lang.Thread;publicclassTestSelectorprivatestaticfinalintMAXSIZE=5;publicstaticfinalvoidmain(Stringargc)Selectorsels=newSelectorMAXSIZE;tryfor(inti=0;iMAXSIZE;+i)selsi=Selector.open();/selsi.close();Thread.sleep(30000);catch(Exceptionex)thrownewRuntimeException(ex);這個(gè)程序什么也沒(méi)有,就是做5次Selector.o
8、pen(),然后休息30秒,以便我使用ProcessExplorer工具來(lái)查看進(jìn)程。程序編譯沒(méi)有問(wèn)題,運(yùn)行起來(lái),在ProcessExplorer中看到下面的對(duì)話框:(居然有10個(gè)連接,從連接端口我們可以知道,互相連接,如:第一個(gè)連第二個(gè),第二個(gè)又連第一個(gè))不由得贊嘆我們的Java啊,先不說(shuō)這是不是一件愚蠢的事。至少可以肯定的是,Java在消耗寶貴的系統(tǒng)資源方面,已經(jīng)可以趕的上某些蠕蟲病毒了。如果不信,不妨把上面程序中的那個(gè)MAXSIZE的值改成65535試試,不一會(huì)你就會(huì)發(fā)現(xiàn)你的程序有這樣的錯(cuò)誤了:(在我的XP機(jī)器上大約運(yùn)行到2000個(gè)Selector.open()左右)Exceptionin
9、threadmainjava.lang.RuntimeException:java.io.IOException:UnabletoestablishloopbackconnectionatTest.main(Test.java:18)Causedby:java.io.IOException:Unabletoestablishloopbackconnectionatsun.nio.ch.PipeImpl$Initializer.run(UnknownSource)atjava.security.AccessController.doPrivileged(NativeMethod)atsun.ni
10、o.ch.PipeImpl.(UnknownSource)atsun.nio.ch.SelectorProviderImpl.openPipe(UnknownSource)atjava.nio.channels.Pipe.open(UnknownSource)atsun.nio.ch.WindowsSelectorImpl.(UnknownSource)atsun.nio.ch.WindowsSelectorProvider.openSelector(UnknownSource)atjava.nio.channels.Selector.open(UnknownSource)atTest.mai
11、n(Test.java:15)Causedby:.SocketException:Nobufferspaceavailable(maximumconnectionsreached?):connectatsun.nio.ch.Net.connect(NativeMethod)atsun.nio.ch.SocketChannelImpl.connect(UnknownSource)atjava.nio.channels.SocketChannel.open(UnknownSource).9more四、繼續(xù)調(diào)查:如此跨平臺(tái)當(dāng)然,沒(méi)人像我們這么變態(tài)寫出那么多的Selector.open(),但這正好可
12、以讓我們來(lái)明白Java背著大家在干什么事。上面的那些“愚蠢連接”是在Windows平臺(tái)上,如果不出意外,Unix/Linux下應(yīng)該也差不多吧。于是我們把上面的程序放在Linux下跑了跑。使用netstat命令,并沒(méi)有看到自己和自己的Socket連接。貌似在Linux上使用了和Windows不一樣的機(jī)制?!如果在Linux上不建自己和自己的TCP連接的話,那么文件描述符和端口都會(huì)被省下來(lái)了,是不是也就是說(shuō)我們調(diào)用65535個(gè)Selector.open()的話,應(yīng)該不會(huì)出現(xiàn)異常了??上?,在實(shí)現(xiàn)運(yùn)行過(guò)程序當(dāng)中,還是一樣報(bào)錯(cuò):(大約在400個(gè)Selector.open()左右,還不如Windows)E
13、xceptioninthreadmainjava.lang.RuntimeException:java.io.IOException:ToomanyopenfilesatTest1.main(Test1.java:19)Causedby:java.io.IOException:Toomanyopenfilesatsun.nio.ch.IOUtil.initPipe(NativeMethod)atsun.nio.ch.EPollSelectorImpl.(EPollSelectorImpl.java:49)atsun.nio.ch.EPollSelectorProvider.openSelect
14、or(EPollSelectorProvider.java:18)atjava.nio.channels.Selector.open(Selector.java:209)atTest1.main(Test1.java:15)我們發(fā)現(xiàn),這個(gè)異常錯(cuò)誤是“Toomanyopenfiles”,于是我想到了使用lsof命令來(lái)查看一下打開的文件??吹搅擞幸恍﹑ipe文件,一共5對(duì),10個(gè)(當(dāng)然,管道從來(lái)都是成對(duì)的)。如下圖所示。文件駕輯W繆鞘hdi3nCHiitYtu!hdEnfltfeuitU叨盹/Iib/1d-2.S.l.eo/dev/pts/0Zdev/pts/O/dev/pts/O/nsr/lib
15、打糊打凱牆-&s-uft-l.G.0.O(3/jA學(xué)tb:mrra摘論ZjaiT-VIJJjaw25578hchenjavg2557Slichejavai2578hchen.jaira25E78LclieiiJava.2&578掄出壯t,$arjava_25573hchenjawsi2578hcheti伽電hhen.Java25578hchenjaira.25E78licheejawa25578hchen.255TShchetljava2&57Sbchenjava.2557Shchenjava2557Shchen.Java2557ShehsnJava.25578hchen.jmvs25578h
16、chesijava25&73hcJ-enjava25刃呂hchen.hchenJubtrntLi;VJ$Lch&nJ&ubuirtii:缶mcnl2u3r010914S997058222S50210oon-ooooooorT-vrr-Tr-OTJTJTJOT-TCTx1rxTx亠TTxTvh-.J.VTx_EETA*FFOFFOFFOFFOFFO6676G766TG67667oooooooonvoooooo000-0032621326217249262292G227249E6Z3S262373492G2492624734S63724pipeUipe/aiKn_iDad?:jleventpol1
17、Pipepips/anninode-:Intpol11pupeplr巳AtiFi:evenxpol1pip。Pipe/anofLinode:eirtpal1JPiflepipe/anfin_iiKdeiento!j可見,Selector.open()在Linux下不用TCP連接,而是用pipe管道??磥?lái),這個(gè)pipe管道也是自己給自己的。所以,我們可以得出下面的結(jié)論:Windows下,Selector.open()會(huì)自己和自己建立兩條TCP鏈接。不但消耗了兩個(gè)TCP連接和端口,同時(shí)也消耗了文件描述符。Linux下,Selector.open。會(huì)自己和自己建兩條管道。同樣消耗了兩個(gè)系統(tǒng)的文件描述
18、符。估計(jì),在Windows下,Sun的JVM之所以選擇TCP連接,而不是Pipe,要么是因?yàn)樾阅艿膯?wèn)題,要么是因?yàn)橘Y源的問(wèn)題。可能,Windows下的管道的性能要慢于TCP鏈接,也有可能是Windows下的管道所消耗的資源會(huì)比TCP鏈接多。這些實(shí)現(xiàn)的細(xì)節(jié)還有待于更為深層次的挖掘。但我們至少可以了解,原來(lái)Java的Selector在不同平臺(tái)上的機(jī)制。五、迷惑不解:為什么要自己消耗資源?令人不解的是為什么我們的Java的NewI/O要設(shè)計(jì)成這個(gè)樣子?如果說(shuō)老的I/O不能多路復(fù)用,如下圖所示,要開N多的線程去挨個(gè)偵聽每一個(gè)Channel(文件描述符),如果這樣做很費(fèi)資源,且效率不高的話。那為什么在新
19、的I/O機(jī)制依然需要自己連接自己,而且,還是重復(fù)連接,消耗雙倍的資源?通過(guò)WEB搜索引擎沒(méi)有找到為什么。只看到N多的人在報(bào)BUG,但SUN卻沒(méi)有任何解釋。下面一個(gè)圖展示了,老的IO和新IO的在網(wǎng)絡(luò)編程方面的差別??雌饋?lái)NIO的確很好很強(qiáng)大。但似乎比起C/C+來(lái)說(shuō),Java的這種實(shí)現(xiàn)會(huì)有一些不必要的開銷。SockrtChann日Ireist-srregale-ThreadOldIOSmanythreadsLiook白dcmpeadnngEpoinnmiLtijlesocketsSwK1-SacksKJacketSakatInputSfreiLmInputstrea-Ti1npulStBanSot
20、kelChdnnelScckBEChann已setect1IL111BireadThreadThreadThraarirsa.dSockedSocketSockSocket*珂ewIO,singletlueadaockeiloiLselection六、它山之石:從Apache的Mina框架了解Selector上面的調(diào)查沒(méi)過(guò)多長(zhǎng)時(shí)間,正好同學(xué)趙錕的一個(gè)同事也在開發(fā)網(wǎng)絡(luò)程序,這位仁兄使用了Apache的Mina框架。當(dāng)我們把Mina框架的源碼研讀了一下后。發(fā)現(xiàn)在Mina中有這么一個(gè)機(jī)制:Mina框架會(huì)創(chuàng)建一個(gè)Work對(duì)象的線程。Work對(duì)象的線程的run()方法會(huì)從一個(gè)隊(duì)列中拿出一堆Channel
21、,然后使用Selector.select()方法來(lái)偵聽是否有數(shù)據(jù)可以讀/寫。最關(guān)鍵的是,在select的時(shí)候,如果隊(duì)列有新的Channel加入,那么,Selectorselect()會(huì)被喚醒,然后重新select最新的Channel集合。要喚醒select方法,只需要調(diào)用Selector的wakeup()方法。對(duì)于熟悉于系統(tǒng)調(diào)用的C/C+程序員來(lái)說(shuō),一個(gè)阻塞在select上的線程有以下三種方式可以被喚醒:有數(shù)據(jù)可讀/寫,或出現(xiàn)異常。阻塞時(shí)間到,即timeout。收到一個(gè)non-block的信號(hào)??捎蒶ill或pthread_kill發(fā)出。所以,Selector.wakeup()要喚醒阻塞的se
22、lect,那么也只能通過(guò)這三種方法,其中:第二種方法可以排除,因?yàn)閟elect一旦阻塞,應(yīng)無(wú)法修改其timeout時(shí)間。而第三種看來(lái)只能在Linux上實(shí)現(xiàn),Windows上沒(méi)有這種信號(hào)通知的機(jī)制。所以,看來(lái)只有第一種方法了。再回想到為什么每個(gè)Selector.open(),在Windows會(huì)建立一對(duì)自己和自己的loopback的TCP連接;在Linux上會(huì)開一對(duì)pipe(pipe在Linux下一般都是成對(duì)打開),估計(jì)我們能夠猜得出來(lái)那就是如果想要喚醒select,只需要朝著自己的這個(gè)loopback連接發(fā)點(diǎn)數(shù)據(jù)過(guò)去,于是,就可以喚醒阻塞在select上的線程了。七、真相大白:可愛的Java你太
23、不容易了使用Linux下的strace命令,我們可以方便地證明這一點(diǎn)。參看下圖。圖中,請(qǐng)注意下面幾點(diǎn):26654是主線程,之前我輸出notifytheselect字符串是為了做一個(gè)標(biāo)記,而不至于迷失在大量的stracelog中。26662是偵聽線程,也就是select阻塞的線程。圖中選中的兩行。26654的write正是wakeup()方法的系統(tǒng)調(diào)用,而緊接著的就是26662的epoll_wait的返回。文件輪挹查春續(xù)端標(biāo)簽蒂勵(lì)Of/jayahdhanJOLixnytLi;*j萍再2S6S1get.timeofcly(120656788,S631SO,EJULLJ=0:茨拠1gettinieo
24、fday(1206567S61,呂63792hNULL)二0.26651cloci.gettimeCCLra.RELIIWE,120656TB64,0643T05S6J-)=0266S1futex25G54,futesre&uoie)-1HfHEDOUT(ConnecticntinedoutTOC o 1-5 h z26S54futex0k80S98dO?FUTB_WAKE?1)=0266&4cl(CLOCLMDTONIC,3S732r773994559)=026654writed,notifytheseleet?F,17)土1736654write(5RW1unfinisfiedg6E5EJ
25、、卸oH_wait劭nmedEFDLUtb(諂羽已u6辰侶082T795525413352適h1伍乂-心三12fi654vr譏g1)=1255&4i.writeresumed=1:26E523et-timeo-fday(tmfijiishiel2G654TunapSTdaiOOO,12288.PROT.REtD|PROfT.WRIIT|PROT.EJCEC.W_PRIVATE|JIAP.FIJO|JIAP_AUDM|7MDIEJWNQEESEBVE,-1,02662.gattine&f-dajjresusie(12065GT7ES4,3S757E),HULL)=0266M、-0i1da4000
26、.266S2resiiJ(S.266&4rt_sigpKJcrk(JSG.SEDMSKpL26562飛T爲(wèi)128)=126654J、.rt_sjgprocmaftrssmiEcI-NULLt=0Iit-12G6G2vrite(l?dselectreturn,ISunfiiii51Kd從上圖可見,這和我們之前的猜想正好一樣??梢?,JDK的Selector自己和自己建的那些TCP連接或是pipe,正是用來(lái)實(shí)現(xiàn)Selector的notify和wakeup的功能的。這兩個(gè)方法完全是來(lái)模仿Linux中的的kill和pthread_kill給阻塞在select上的線程發(fā)信號(hào)的。但因?yàn)榘l(fā)信號(hào)這個(gè)東西并不是一
27、個(gè)跨平臺(tái)的標(biāo)準(zhǔn)(pthread_kill這個(gè)系統(tǒng)調(diào)用也不是所有Unix/Linux都支持的),而pipe是所有的Unix/Linux所支持的,但Windows又不支持,所以,Windows用了TCP連接來(lái)實(shí)現(xiàn)這個(gè)事。關(guān)于Windows,我一直在想,Windows的防火墻的設(shè)置是不是會(huì)讓Java的類似的程序執(zhí)行異常呢?呵呵。如果不知道Java的SDK有這樣的機(jī)制,誰(shuí)知道會(huì)有多少個(gè)程序?yàn)榇艘鸬膯?wèn)題度過(guò)多少個(gè)不眠之夜,尤其是Java程序員。八、后記文章到這里是可以結(jié)束了,但關(guān)于JavaNIO的Selector引出來(lái)的其它話題還有許多,比如關(guān)于GNU的Java編譯器又是如何,它是否會(huì)像Sun的Jav
28、a解釋器如此做傻事?我在這里先賣一個(gè)關(guān)子,關(guān)于GNU的Java編譯器,我會(huì)在另外一篇文章中講述,近期發(fā)布,敬請(qǐng)期待。關(guān)于本文中所使用的實(shí)驗(yàn)平臺(tái)如下:Windows:WindowsXP+SP2,SunJ2SE(build1.7.0-ea-b23)Linux:Ubuntu7.10+LinuxKernel2.6.22-14-generic,J2SE(build1.6.0_03-b05)本文主要的調(diào)查工作由我的大學(xué)同學(xué)趙錕完成,我?guī)推潋?yàn)證調(diào)查成果及猜想。在此也向大家介紹我的大學(xué)同學(xué)趙錕,他也是一個(gè)技術(shù)高手,在軟件開發(fā)方面,特別是Unix/LinuxC/C+方面有著相當(dāng)?shù)墓Φ?,相信自此以后,?huì)有很多文章
29、會(huì)由我和他一同發(fā)布。JavaNIO類庫(kù)Selector機(jī)制解析(續(xù))在前些天的JavaNIO類庫(kù)Selector機(jī)制解析文章中,我們知道了下面的事情:Sun的JVM在實(shí)現(xiàn)Selector上,在Linux和Windows平臺(tái)下的細(xì)節(jié)。Selector類的wakeup()方法如何喚醒阻塞在select。系統(tǒng)調(diào)用上的細(xì)節(jié)。先給大家做一個(gè)簡(jiǎn)單的回顧,在Windows下,Sun的Java虛擬機(jī)在Selector.open()時(shí)會(huì)自己和自己建立loopback的TCP鏈接;在Linux下,Selector會(huì)創(chuàng)建pipe。這主要是為了Selector.wakeup()可以方便喚醒阻塞在select()系統(tǒng)調(diào)
30、用上的線程(通過(guò)向自己所建立的TCP鏈接和管道上隨便寫點(diǎn)什么就可以喚醒阻塞線程)我們知道,無(wú)論是建立TCP鏈接還是建立管道都會(huì)消耗系統(tǒng)資源,而在Windows上,某些Windows上的防火墻設(shè)置還可能會(huì)導(dǎo)致Java的Selector因?yàn)榻⒉黄餷oopback的TCP鏈接而出現(xiàn)異常。而在我的另一篇文章用GDB調(diào)試Java程序中介紹了另一個(gè)Java的解釋器GNU的gj以及編譯器gcj,不但可以比較高效地運(yùn)行Java程序,而且還可以把Java程序直接編譯成可執(zhí)行文件。GNU的之所以要重做一個(gè)Java的編譯和解釋器,其一個(gè)重要原因就是想解釋Sun的JVM的效率和資源耗費(fèi)問(wèn)題。當(dāng)然,GNU的Java編
31、譯/解釋器并不需要考慮太多復(fù)雜的平臺(tái),他們只需要專注于Linux和衍生自UnixSystemV的操作系統(tǒng),對(duì)于開發(fā)人員來(lái)說(shuō),離開了Windows,一切都會(huì)變得簡(jiǎn)單起來(lái)。在這里,讓我們看看GNU的gij是如何解釋Selector.open()和Selector.wakeup()的。同樣,我們需要一個(gè)測(cè)試程序。在這里,為了清晰,我不會(huì)例出所有的代碼,我只給出我所使用的這個(gè)程序的一些關(guān)鍵代碼。我的這個(gè)測(cè)試程序中,和所有的Socket程序一樣,下面是一個(gè)比較標(biāo)準(zhǔn)的框架,當(dāng)然,這個(gè)框架應(yīng)該是在一個(gè)線程中,也就是一個(gè)需要繼承Runnable接口,并實(shí)現(xiàn)run()方法的一個(gè)類。(注意:其中的s是一個(gè)成員變量
32、,是Selector類型,以便主線程序使用)/生成一個(gè)偵聽端ServerSocketChannelssc=ServerSocketChannel.open();/將偵聽端設(shè)為異步方式ssc.configureBlocking(false);/生成一個(gè)信號(hào)監(jiān)視器s=Selector.open();/偵聽端綁定到一個(gè)端口ssc.socket().bind(newInetSocketAddress(port);/設(shè)置偵聽端所選的異步信號(hào)OP_ACCEPTssc.register(s,SelectionKey.OP_ACCEPT);System.out.println(echoserverhasbeensetup);while(true)intn=s.select();if(n=0)/沒(méi)有指定的I/O事件發(fā)生continue;Iteratorit=s.selectedKeys().iterator();while(it.hasNext()Selectio
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度城鄉(xiāng)實(shí)體地域劃分與土地利用規(guī)劃合同3篇
- 2025年度體育場(chǎng)館周邊臨時(shí)停車位租賃管理協(xié)議3篇
- 2025年度文化創(chuàng)意產(chǎn)業(yè)出借咨詢及合作開發(fā)合同4篇
- 2025年度汽車零部件OEM貼牌生產(chǎn)協(xié)議2篇
- 2025年度特色民宿租賃服務(wù)合同范本4篇
- 《電池技術(shù)教程》課件
- 2025年度租賃汽車保險(xiǎn)理賠服務(wù)合同模板4篇
- 2025年物業(yè)管理員考試輔導(dǎo)教材基本知識(shí)問(wèn)答合同3篇
- 2025年湖南懷化信合勞務(wù)有限公司招聘筆試參考題庫(kù)含答案解析
- 2025年浙江湖州建欣商貿(mào)有限公司招聘筆試參考題庫(kù)含答案解析
- 臨床醫(yī)學(xué)院畢業(yè)實(shí)習(xí)管理-new-new課件
- 阻燃材料的阻燃機(jī)理建模
- PLC控制系統(tǒng)合同(2024版)
- CJT 511-2017 鑄鐵檢查井蓋
- ISO15189培訓(xùn)測(cè)試卷及答案
- JJG(交通) 171-2021 超聲式成孔質(zhì)量檢測(cè)儀檢定規(guī)程
- 氣象衛(wèi)星技術(shù)在軍事中的應(yīng)用
- 配電工作組配電網(wǎng)集中型饋線自動(dòng)化技術(shù)規(guī)范編制說(shuō)明
- 介入科圍手術(shù)期護(hù)理
- 化驗(yàn)員個(gè)人自查自糾報(bào)告
- 食品良好操作規(guī)范(GMP)和食品衛(wèi)生標(biāo)準(zhǔn)操作程序(SSOP)課件
評(píng)論
0/150
提交評(píng)論