本文主要介紹一下BIO、NIO、AIO
Block-IO:基於字節流的InputStream和OutputStream,基於字符流的Reader和Writer,同時也包括Socket那些java.net包下的類等。
BIO的屬性是同步阻塞的,優點就是寫起來簡單缺點是效率太低。
NonBlock-IO:在JDK4中引入了NIO,它是一種構建多路複用的,同步非阻塞的IO操作提供了Selector、Channel、Buffer等新的抽象,同時提供了更底層的數據操作方式。
下面介紹一個NIO的三大核心:Channels,Buffers,Selectors。
NIO-Channel
Channel有點像流,一個的數據都是從Channel開始然後讀到Buffer中再從Buffer寫到Channel中。
NIO的Channels有以下幾種類型,從方法名可以看出有UDP的Channel有文件Channel還有TCP的Channel:
- FileChannel
- DatagramChannel
- SocketChannel
- ServerSocketChannel
其中,FileChannel中有兩個有意思的方法:
transferTo
:把FileChannel中的數據拷貝到另外一個ChanneltransferFrom
:把另外一個Channel中的數據拷貝到FileChannel
該Channel避免了兩次用戶態和內核態之間的上下文切換,即“零拷貝”,效率較高。
NIO-Buffer
有以下幾種類型,進行緩衝流的數據屬性修飾:
- ByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
- MappedByteBuffer
NIO-Selector
如果連接打開了多個通道,但是每個通道的流量都很低就可以使用Selector。
另外NIO的底層也採用了IO的多路複用:調用系統級別的select/poll/epoll,意思就是說可以單線程處理多路IO。
然後簡單介紹一下三者以及三者的區別:
支持一個線程所能打開的最大連接數
select:單個進程能打開的最大連接數由FD_SETSIZE宏定義,其大小是32個整數的大小,我們可以對其進行修改,然後重新編譯內核,但是性能無法保證,需要進一步測試
poll:本質上和select沒有區別,但是沒有最大連接數的限制,原因是因爲他是基於鏈表去存儲的
epoll:雖然連接數由上線,但是很大,1G內存的機器可以打開10萬左右的連接
面對文件句柄DF劇增之後也會帶來IO效率問題
select:因爲每次調用的時候都會對連接進行線性遍歷,所以隨着FD的增加會造成遍歷速度的線性下降的性能問題
poll:同上
epoll:由於epoll是根據每個fd上的callback函數來實現的,只有活躍的socket纔會主動調用callback,所以在活躍socket較少的情況下,使用epoll不會有線性下降的性能問題,但是所有socket都很活躍的情況下可能會有性能上的問題
在消息的傳遞方式上
select:內核需要將消息傳遞到用戶空間,需要內核的拷貝工作
poll:同上
通過內核和用戶空間共享一塊內存來實現性能很高
JDK7又引入了AIO:基於事件和回調機制
AIO屬於異步模型,也就是說處理IO的時候可以同時處理別的事情,那我們應該如何進一步加工處理結果呢?
- 基於回調:實現CompletionHandler接口,調用的時候觸發回調函數;
- 返回Future:通過isDone()查看是否準備好,通過get()等待返回數據