你好,我是彤哥,本篇是netty系列的第五篇。html
上一章咱們一塊兒學習瞭如何使用Java原生NIO實現羣聊系統,這章咱們一塊兒來看看Java NIO的核心組件之一——Channel。java
首先,我想說的最重要的一個點是,學習NIO思惟必定要從BIO那種一個鏈接一個線程的模式轉變成多個鏈接(Channel)共用一個線程來處理的這種思惟。linux
> 1個Connection = 1個Socket = 1個Channel,這幾個概念能夠看做是等價的,都表示一個鏈接,只不過是用在不一樣的場景中。編程
若是單從阻塞/非阻塞的角度來看的話,IO能夠分紅兩大類,一類是Blocking IO,一類是Non-blocking IO,像IO五種模型中的後四種其實均可以看做是非阻塞型IO,只是各自使用的手段不相同罷了。數組
在Java中,咱們說的非阻塞IO或者說NIO(New IO)主要是指多路複用IO,底層可使用select/poll/epoll等技術實現。網絡
另外,在Java1.7的時候引入了NIO2,這個主要是指異步IO模型,也就是咱們常說的AIO,底層徹底使用異步回調的方式來實現。架構
可是,因爲AIO這項技術在linux操做系統上還不太成熟,因此咱們一般也不會說太多關於這方面的內容。dom
在後面咱們學習Netty的時候會再次講到這三種IO模型,能夠看到Netty是徹底支持三種IO的,可是它把OIO(BIO)和AIO都給deprecated了,也進一步說明了AIO的不成熟性。異步
好了,扯了一下思惟轉變的問題,下面正式進入今天的內容——Java NIO核心組件之Channel。socket
咱們先來看看Java中對於Channel的定義,位於java.nio.channels.Channel類的註釋上:
> A nexus for I/O operations. > 本文來源工從號彤哥讀源碼 > A channel represents an open connection to an entity such as a hardware device, a file, a network socket, or a program component that is capable of performing one or more distinct I/O operations, for example reading or writing.
第一句,它是IO操做的一種鏈接。
> nexus, the means of connection between things linked in series.
第二句,Channel表明到實體的開放鏈接,這個實體能夠是硬件,文件,網絡套接字,或者程序組件,而且能夠執行一個或多個不一樣的IO操做,例如,讀或寫。
簡單點講,Channel就是實體與實體之間的鏈接,好比,操做文件可使用FileChannel,操做網絡可使用SocketChannel等。
BIO是面向流(Stream)編程的,流又分紅InputStream和OutputStream,那麼Channel和Stream有什麼區別呢?
Channel能夠同時支持讀和寫,而Stream只能支持單向的讀或寫(因此分紅InputStream和OutputStream)
Channel支持異步讀寫,Stream一般只支持同步
Channel老是讀向(read into)Buffer,或者寫自(write from)Buffer(有點繞,以Channel爲中心,從Channel中讀出數據到Buffer,從Buffer中往Channel寫入數據)
下面列舉了JDK中比較重要的實現方式:
public class FileChannelTest { public static void main(String[] args) throws IOException { // 從文件獲取一個FileChannel FileChannel fileChannel = new RandomAccessFile("D:\\object.txt", "rw").getChannel(); // 聲明一個Byte類型的Buffer ByteBuffer buffer = ByteBuffer.allocate(10); // 將FileChannel中的數據讀出到buffer中,-1表示讀取完畢 // buffer默認爲寫模式,本文來源工從號彤哥讀源碼 // read()方法是相對channel而言的,相對buffer就是寫 while ((fileChannel.read(buffer)) != -1) { // buffer切換爲讀模式 buffer.flip(); // buffer中是否有未讀數據 while (buffer.hasRemaining()) { // 未讀數據的長度 int remain = buffer.remaining(); // 聲明一個字節數組 byte[] bytes = new byte[remain]; // 將buffer中數據讀出到字節數組中 buffer.get(bytes); // 打印出來 System.out.println(new String(bytes, StandardCharsets.UTF_8)); } // 清空buffer,爲下一次寫入數據作準備 // clear()會將buffer再次切換爲寫模式 buffer.clear(); } } }
能夠看到,Channel與Buffer是息息相關的。注意這裏的讀寫方法,調用者是誰就以誰爲核心,channel.read()就表示從channel讀出數據,buffer.get()就表示從buffer讀出數據,這跟傳統編程的角度不太同樣的地方。
今天咱們學習了Java NIO核心組件之Channel,它與傳統BIO中的流很相似但又有所區別,且常常與Buffer聯合起來使用,Buffer又是什麼呢?請聽下回分解。
挺不錯的一個網站:
http://tutorials.jenkov.com/java-nio/channels.html
最後,也歡迎來個人工從號彤哥讀源碼系統地學習源碼&架構的知識。