java io nio aio_Java IO、NIO、AIO知识总结
本文主要講述下自己對IO的理解,對IO的用法和細則可能沒有顧慮到。
本文的理解基于以下幾篇文章,他們對各自部分都講的很細,對我理解IO提供了很大幫助。
該文主要講解了Java IO的類體系以及他們各自的用處。
這些文章講解了有關Java Buffer的原理,包括allocate、allocateDirect、map等不同IO方式他們的底層知識。
該文章淺談了NIO、AIO的知識。
正文
首先是我整理的思維導圖
IO的理解
要理解Java IO設計得先了解系統IO,系統不允許程序直接訪問硬盤,而是先將用戶所需數據準備在系統緩沖區中再轉移到用戶內存,所以系統IO操作經過三個地方,1、硬盤 2、系統緩沖 3、用戶進程空間。File就像是對硬盤的抽象,而stream/reader/writer就是對系統緩沖的抽象,而我們用的Buffer就是用戶進程空間的抽象。
IO的體系結構也是很直觀的,對應字節處理和字符處理有了字節流inputstream、outputsream及字符流reader、writer。其中inputsream和reader對應輸入流,outputsream、writer對應輸出流。
根據接受或寫出通道的不同,每個IO流類下衍生出了很多細分類用于處理不同通道。數據來源可以有如下:file、char[]、byte[]、網絡流等。
裝飾者模式
在IO類中有一些類叫FilterXX及它的子類即是裝飾者,比如我們常用的BufferInputSream和BufferOutStream,它可以自動幫我們建立并管理線程中的buffer。
那么什么是裝飾者模式呢?
首先搞清楚裝飾者的目的是:動態、透明地將責任附加到對象上,若要擴展功能,裝飾者提供比繼承更有彈性的替代方案。為了跟裝飾前看起來一樣,它和被裝飾者共同裝配了的同個接口,為了透明增加功能,它持有了被裝配對象(其實是接口),它的方法包括了裝飾功能和喚醒被裝飾者的方法。
Why Decorator?
裝飾者的目的是對類進行拓展,這跟繼承的目標相似。他們特點是什么呢?
l? 動態性 裝飾者對象可以在程序運行階段根據需求動態的拓展功能,那個類需要拓展功能只要將相應裝飾類組合進去。而繼承則需要編譯階段就準備好所有可能性將各種組合可能性編譯好進行選擇。這會造成類冗雜。
l? 解耦性 如果是集成需要層層繼承,而上層類的功能改變勢必會影響下級類的功能。裝飾者則不會。
l? 裝飾者(和繼承)可以在被裝飾者的行為上擴展行為,也可以完全替代被裝飾者的行為.
l? 裝飾者會導致設計中出現許多小對象,如果過度使用,會讓程序變得很復雜。
l? 當只能獲取類對象沒有class文件時只能用裝飾者模式進行加強。
NIO的理解
NIO是一種非阻塞式的IO,要理解它我們得先解決幾個概念。
系統IO階段: 1、數據準備階段(系統從磁盤讀取) 2、將系統緩沖數據轉移到用戶本地內存階段。
什么是阻塞?非阻塞?
答:阻塞非阻塞注重的是數據準備階段線程有沒有造成線程等待,如果數據準備階段線程需一直等待則是阻塞的,否則是非阻塞。
什么是同步?異步?
答:同步異步注重的是整個IO過程有沒有造成IO等待,一些非阻塞IO雖然系統準備階段沒有造成等待,但將數據從內核緩沖區轉移到用戶內存里還是需要等待。
五種IO模型
由于篇幅有限,不重點講IO模型,觀點基于《UNIIX網絡編程卷1:套接字聯網API》 第六章。
同步阻塞IO:會造成整個IO過程等待。
同步非阻塞IO:系統準備數據階段不會造成等待。
信號式IO:系統準備階段不會造成等待,并且系統準備完成會發送信號給線程。
IO復用:由一個線程管理多個IO,底層調用時select和epoll(select需論詢,epoll信號驅動),多個IO只要有一個準備好就線程就不會被阻塞,有效減少了系統準備階段等待時間。
異步IO:整個IO無需等待。完成時返回成功指示。
回到我們整體NIO,很明顯NIO借用的是IO復用的思想。NIO常使用的三個類即是Selector、Buffer、Channel 。使用的方式就是將Channel注冊到selector內,輪詢到那個IO可用就在Channel和Buffer間進行讀寫信息。
Selector有三種選擇方法:select()、select(long timeout)、selectNow();前兩種是阻塞式的,如果一個都沒準備好還是會被阻塞,selectNow()是非阻塞式的,它能立即返回是否準備好的信號。
同樣繼承AbstractSelectableChannel也可以通過設置
NIO中的Buffer分配方式,ByteBuffer.allocate()、ByteBuffer().allocateDirect()以及MappedByteBuffer、TransrferTo()
普通IO方式是通過ByteBuffer.allocate(),在? Java堆上分配內存,因此系統IO過程是:硬盤→系統緩沖→用戶內存空間→系統緩沖→硬盤。
而ByteBuffer().allocateDirect()則是在native堆上分配內存,減少了native堆到Java堆中的復制,加快了速度,但也失去了Java GC的便利性。
MappedByteBuffer:直接建立用戶空間與硬盤間的映射,IO過程省略了數據復制到系統內核緩沖的步驟。這里有個問題是為什么需要系統內核緩沖?因為我們IO時往往會繼續讀取局部上下文,系統為了提高IO效率,直接在內核建立緩沖區緩沖IO數據的上下文以便接下來使用,但如果我們要IO大文件,文件大小超過系統緩沖,這樣緩沖區顯然是無意義的,因此有了這種方法來解決大文件的IO。
TransferTO() 它是以上方法的包裝,如果傳遞對象是FileChannel,則使用MappedByteBuffer的方式,如果是其他channel則使用allocateDirect()方式。
AIO
AIO是完全的異步IO,它實現的核心是異步通道AsynchronizedXXChannel和獲取異步結果的接口Future。
異步通道進行讀寫時會另開一個線程進行IO操作,操作完成它會將改變接受結果類的完成信號并且將結果賦予到接收結果類(Future)上,我們需要結果時,通過訪問接收類信號量,是則獲取結果。
總結
以上是生活随笔為你收集整理的java io nio aio_Java IO、NIO、AIO知识总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java magic number_Ma
- 下一篇: java实现下载压缩文件_java实现文