1. IO基本實(shí)現(xiàn)
1.1 字節(jié)流(stream)
個(gè)人理解: 以字節(jié)為單位對(duì)文件本身直接操作。
主要接口:
InputStream & OutputStream
主要實(shí)現(xiàn):
FileInputStream & FileOutputStream
FilterInputStream & FilterOutputStream
ByteArrayInputStream & ByteArrayOutputStream
1.2 字符流(buffer)
個(gè)人理解:以字符為單位利用緩沖區(qū)對(duì)文件操作,具體讀(寫)操作會(huì)先讀(寫)緩沖區(qū)囤采。
關(guān)于字節(jié)流和字符流的區(qū)別
實(shí)際上字節(jié)流在操作的時(shí)候本身是不會(huì)用到緩沖區(qū)的醋旦,是文件本身的直接操作的衔憨,但是字符流在操作文件的時(shí)候是會(huì)用到緩沖區(qū)的彼绷,是通過(guò)緩沖區(qū)來(lái)操作文件的澎迎。
讀者可以試著將上面的字節(jié)流和字符流的程序的最后一行關(guān)閉文件的代碼注釋掉乱投,然后運(yùn)行程序看看送爸。你就會(huì)發(fā)現(xiàn)使用字節(jié)流的話铛嘱,文件中已經(jīng)存在內(nèi)容,但是使用字符流的時(shí)候袭厂,文件中還是沒(méi)有內(nèi)容的墨吓,這個(gè)時(shí)候就要刷新緩沖區(qū)。
IO缺點(diǎn)
按字節(jié)操作纹磺,效率不高, 大部分線程都在阻塞帖烘,浪費(fèi)計(jì)算資源;
當(dāng)數(shù)據(jù)源沒(méi)有數(shù)據(jù)橄杨,則IO阻塞秘症。
2. NIO (全稱java non-blocking IO, 無(wú)阻塞IO)
在了解NIO之前,先搞清楚Java程序文件讀寫和虛擬內(nèi)存的原理式矫。
Java程序文件讀寫(IO)
當(dāng)應(yīng)用程序需要讀取文件的時(shí)候乡摹,內(nèi)核首先通過(guò)DMA技術(shù)將文件內(nèi)容從磁盤讀入內(nèi)核中的buffer,然后Java應(yīng)用進(jìn)程再?gòu)膬?nèi)核的buffer將數(shù)據(jù)讀取到應(yīng)用程序的buffer采转。
簡(jiǎn)單點(diǎn)說(shuō):先從Disk(硬盤)讀到Kernel(內(nèi)核)聪廉,再?gòu)腒ernel(內(nèi)核)讀到進(jìn)程(Process)的buffer。下圖就是IO讀工作原理:
為了提升I/O效率和處理能力故慈,操作系統(tǒng)采用虛擬內(nèi)存的機(jī)制锄列。
虛擬內(nèi)存(交換內(nèi)存)
虛擬內(nèi)存實(shí)際上是Disk上得文件,主要作用有兩個(gè):
-
不同的虛擬內(nèi)存可以映射到相同的物理內(nèi)存惯悠。
說(shuō)白了邻邮,就是硬盤內(nèi)不同的文件,可以映射到相同的物理內(nèi)存地址克婶。
根據(jù)這個(gè)原理筒严,可以簡(jiǎn)化文件讀取流程,提升讀取效率情萤,效果如下圖所示:
NIO工作原理
通過(guò)使用虛擬內(nèi)存技術(shù)鸭蛙,將應(yīng)用程序的buffer和內(nèi)核的buffer都作為虛擬內(nèi)存,并且兩塊不同的虛擬內(nèi)存指向相同的物理內(nèi)存筋岛,內(nèi)核通過(guò)DMA將數(shù)據(jù)讀取到buffer的時(shí)候娶视,應(yīng)用程序就可以直接使用這些數(shù)據(jù)了。
簡(jiǎn)單點(diǎn)說(shuō): 先從Disk讀到Kernel的虛擬內(nèi)存(硬盤的文件),因?yàn)閗ernel的虛擬內(nèi)存和應(yīng)用程序的虛擬內(nèi)存映射相同的物理內(nèi)存肪获,所以應(yīng)用程序可以直接用了寝凌,不用讀多一次。 通過(guò)使用虛擬內(nèi)存(Disk的文件)孝赫, 應(yīng)用程序可以使用比物理內(nèi)存所能容納得大得多的內(nèi)存较木,并且也能夠提高I/O效率。當(dāng)物理內(nèi)存中的數(shù)據(jù)不使用的時(shí)候青柄,可以將物理內(nèi)存中的數(shù)據(jù)放到虛擬內(nèi)存中伐债,操作系統(tǒng)就可以騰出物理內(nèi)存空間存儲(chǔ)新的要處理的數(shù)據(jù)。當(dāng)需要使用虛擬內(nèi)存中的數(shù)據(jù)時(shí)致开,再可以把虛擬內(nèi)存中的數(shù)據(jù)加載到物理內(nèi)存中峰锁。因此物理內(nèi)存可以看做時(shí)虛擬內(nèi)存中存放數(shù)據(jù)的cache。而上面所述的cache虛擬內(nèi)存數(shù)據(jù)的過(guò)程双戳,對(duì)應(yīng)用程序來(lái)說(shuō)時(shí)透明的祖今,它可以像處理物理內(nèi)存數(shù)據(jù)一樣處理虛擬內(nèi)存中的數(shù)據(jù)。
簡(jiǎn)單點(diǎn)說(shuō):因?yàn)橛刑摂M內(nèi)存(緩存)拣技,應(yīng)用程序能夠更加快速的讀寫比物理內(nèi)存更大的文件。
知道上面虛擬內(nèi)存原理耍目,繼續(xù)NIO的核心內(nèi)容膏斤。
Java NIO 主要由以下三個(gè)核心部分組成:
Channel 通道
通道是 I/O 傳輸發(fā)生時(shí)通過(guò)的入口,而緩沖區(qū)是這些數(shù) 據(jù)傳輸?shù)膩?lái)源或目標(biāo)邪驮。對(duì)于離開緩沖區(qū)的傳輸莫辨,您想傳遞出去的數(shù)據(jù)被置于一個(gè)緩沖區(qū),被傳送到通道毅访。對(duì)于傳回緩沖區(qū)的傳輸沮榜,一個(gè)通道將數(shù)據(jù)放置在您所提供的緩沖區(qū)中。Buffer 緩沖區(qū)
引入了緩沖區(qū)的概念喻粹,當(dāng)數(shù)據(jù)到達(dá)時(shí)蟆融,可以預(yù)先被寫入緩沖區(qū),再由緩沖區(qū)交給線程守呜,因此線程無(wú)需阻塞地等待IO型酥。-
Selectors 選擇器(監(jiān)管多個(gè)通道)
通道和緩沖區(qū)的機(jī)制,使得線程無(wú)需阻塞地等待IO事件的就緒查乒,但是總是要有人來(lái)監(jiān)管這些IO事件弥喉。這個(gè)工作就交給了selector來(lái)完成,這就是所謂的同步玛迄。Selector允許單線程處理多個(gè) Channel由境。如果你的應(yīng)用打開了多個(gè)連接(通道),但每個(gè)連接的流量都很低蓖议,使用Selector就會(huì)很方便虏杰。
要使用Selector讥蟆,得向Selector注冊(cè)Channel,然后調(diào)用它的select()方法嘹屯。這個(gè)方法會(huì)一直阻塞到某個(gè)注冊(cè)的通道有事件就緒攻询,這就是所說(shuō)的輪詢。一旦這個(gè)方法返回州弟,線程就可以處理這些事件钧栖。
Selector中注冊(cè)的感興趣事件有:
OP_ACCEPT
OP_CONNECT
OP_READ
OP_WRITE
** NIO主要實(shí)現(xiàn):**
- FileChannel:從文件中讀寫數(shù)據(jù)。
- DatagramChannel:能通過(guò)UDP讀寫網(wǎng)絡(luò)中的數(shù)據(jù)婆翔。
- SocketChannel:能通過(guò)TCP讀寫網(wǎng)絡(luò)中的數(shù)據(jù)拯杠。
- ServerSocketChannel:可以監(jiān)聽新進(jìn)來(lái)的TCP連接,像Web服務(wù)器那樣啃奴。對(duì)每一個(gè)新進(jìn)來(lái)的連接都會(huì)創(chuàng)建一個(gè)SocketChannel潭陪。
NIO2
NIO2是Java7 添加了4個(gè)異步通道,分別包括:
- AsynchronousSocketChannel
- AsynchronousServerSocketChannel
- AsynchronousFileChannel
- AsynchronousDatagramChannel
NIO.2 的異步通道 APIs 提供方便的最蕾、平臺(tái)獨(dú)立的執(zhí)行異步操作的標(biāo)準(zhǔn)方法依溯。這使得應(yīng)用程序開發(fā)人員能夠以更清晰的方式來(lái)編寫程序,而不必定義自己的 Java 線程瘟则,此外黎炉,還可通過(guò)使用底層 OS 所支持的異步功能來(lái)提高性能。如同其他 Java API 一樣醋拧,API 可利用的 OS 自有異步功能的數(shù)量取決于其對(duì)該平臺(tái)的支持程度慷嗜。
自己理解: NIO2在原來(lái)的NIO包加入了異步處理的API。
返回Future結(jié)果集丹壕,更好控制IO異步處理庆械。
對(duì)象序列化
序列化的原理:
Serialization(序列化)是一種將對(duì)象以一連串的字節(jié)描述的過(guò)程。
反序列化的原理:
反序列化deserialization是一種將這些字節(jié)重建成一個(gè)對(duì)象的過(guò)程菌赖。
序列化的意義:
Java中缭乘,一切都是對(duì)象,在分布式環(huán)境中經(jīng)常需要將Object從這一端網(wǎng)絡(luò)或設(shè)備傳遞到另一端琉用。
這就需要有一種可以在兩端傳輸數(shù)據(jù)的協(xié)議忿峻。Java序列化機(jī)制就是為了解決這個(gè)問(wèn)題而產(chǎn)生。
如何序列化:
一個(gè)對(duì)象能夠序列化的前提是實(shí)現(xiàn)Serializable接口辕羽,Serializable接口沒(méi)有方法逛尚,更像是個(gè)標(biāo)記。
有了這個(gè)標(biāo)記的Class就能被序列化機(jī)制處理刁愿。
Java序列化算法
- 將對(duì)象實(shí)例相關(guān)的類元數(shù)據(jù)輸出绰寞。
- 遞歸地輸出類的超類描述直到不再有超類。
- 類元數(shù)據(jù)完了以后,開始從最頂層的超類開始輸出對(duì)象實(shí)例的實(shí)際數(shù)據(jù)值滤钱。
- 從上至下遞歸輸出實(shí)例的數(shù)據(jù)觉壶。
serialVersionUID值的重要作用
根據(jù)上面的分析,可以發(fā)現(xiàn)如果一個(gè)類可序列化,serialVersionUID建議給一個(gè)確定的值,不要由系統(tǒng)自動(dòng)生成,否則在增減字段(不能修改字段類型及長(zhǎng)度)時(shí),如果兩邊的類的版本不同會(huì)導(dǎo)致反序列化失敗.
參考:
基于java的nio消息實(shí)現(xiàn)方式優(yōu)缺點(diǎn)分析及示例代碼說(shuō)明
java nio原理和它的優(yōu)點(diǎn)
以上純屬個(gè)人理解,有誤請(qǐng)指正件缸。謝謝铜靶!