1. 程式人生 > >漫談Java IO之基礎篇

漫談Java IO之基礎篇

等待 明顯 分發 限制 以及 經典 內核 很大的 lec

Java的網絡編程如果不是專門搞服務器性能開發或者消息分發,幾乎可能涉及不到。但是它卻是面試找工作必問的一個知識點,涵蓋的知識體系也非常廣泛,從Java底層IO原理到操作系統內核組成,再到網絡TCP、UDP、HTTP的應用實踐....因此,即便是職場多年的老油條,仍然需要時刻復習,更別提我這種只有七秒鐘記憶的小菜鳥了。

Java網絡IO的演化,從最開始JDK1.4之前是基於阻塞的IO;發展到1.4發布後的Nio提供了selector多路復用的機制以及channel和buffer,再到1.7的NIO升級提供了真正的異步api;再發展到後來嶄露頭角的MINA和Netty。因此整個網絡IO編程的學習整理,也會按照下面的幾個步驟來進行:

  1. 網絡IO的基本知識與概念
  2. 普通IO以及BIO服務器
  3. NIO的使用與服務器Hello world
  4. Netty入門與服務器Hello world
  5. Netty深入淺出

今天就簡單的了解下網絡IO需要具備的基本知識與概念。

同步、異步和阻塞、非阻塞

經常聽人提起,同步阻塞服務器或者異步非阻塞服務器,網上有很多的文章針對這個概念作出了講解,每個人理解的貌似都不太一樣。最容易把異步和非阻塞搞混....我這裏簡單的說下自己的理解:

同步synchronous、異步asynchronous,他們的區別就是發起任務後,本身的一個狀態——如果是一直等待結果,那就是同步;如果立即返回,並采用其他的方式得到結果就是異步(比如,狀態、通知、回調)。

舉個例子:
技術分享圖片

  1. 在過去科技不發達的時候,銀行取錢都是排隊的模式。想取錢就得去排隊,直到輪到自己,這就是同步;
  2. 現在去銀行一般直接叫號,然後去休息位置休息打遊戲,登到輪到自己的時候,會有通知,這就是異步;

阻塞blocking、非阻塞non-blocking,則聚焦的是CPU在等待結果的過程中的狀態。比如前面的例子,排隊的過程中什麽也不做就是阻塞;一邊排隊,一遍玩王者榮耀就是非阻塞的。

用戶空間與內和空間

這個概念就涉及操作系統了,為了保護操作系統的安全,會將內存分為用戶空間內核空間兩個部分。如果用戶想要操作內核空間的數據,需要把數據從內和空間拷貝到用戶控件。

技術分享圖片

舉個例子:

服務器接收客戶端發過來的請求,想要進行處理,大致會經過下面幾個步驟:

  1. 服務器的網絡驅動接收到消息,去內核上申請空間;並等待完整的數據包到達(有可能分組傳送,沒傳完...),復制到內核空間;
  2. 數據從內核空間拷貝到用戶空間
  3. 用戶程序進行處理

因此大致可以把接收消息理解為兩個階段:1. 等待數據到達 2. 拷貝到用戶空間

了解了這個過程,就能明白為什麽會出現經典的5大網絡模型了.

五大網絡模型

這幾個網絡模型還是學生時代的時候也看過,但是理解的不夠透徹,也不知道到底有什麽區別。最近網上也看過不少的文章,發現有一些文章引用的小例子不錯,能很簡單的了解這些模型的意思。所以我這邊也借鑒一下:

在大連高新萬達後面有一條叫做金街的小吃街,有一個露天的路邊攤叫做“小紅旗”,主要是做炸臭豆腐和冷面,然後用冷面把臭豆腐卷起來,刷上臭烘烘的醬料,非常好吃。每次路過都能看到不少人在排隊,隊伍長的有種想讓人辭職加盟的感覺....基本上排個隊伍都得半個小時-一個小時吧。

這個排隊的過程,明顯就是上面所說的同步阻塞模式....那我這邊就設想下,如果小紅旗的生意做大了,可以怎麽發展?正好套用下網絡模型的概念...

1. 同步阻塞IO

技術分享圖片

這個就不詳細說了,排隊的過程哪也去不了,如果你還沒有帶手機,排隊的過程中就只能幹瞪眼了。這就是很明顯的同步+阻塞模式。

2. 同步非阻塞IO

技術分享圖片

如果小紅旗的老板搞了一個點菜機,來點單的顧客把自己想吃的劃上,然後等著老板去做,自己可以在這一個小時的時間裏去周圍商場溜達下。但是由於沒有任何通信方式,只能不停的回來問老板,做好了沒有。

回來詢問的時間是由顧客自己掌控的,如果時間很短,那麽可以盡量早的知道臭豆腐炸好沒,但是也會影響逛街的體驗;如果時間很長,有可能臭豆腐早就做好了..結果放的時間長了,反而不好吃了。

因此非阻塞IO基於狀態輪訓的方式,雖然能讓程序在等待的過程中做點其他的事情,但是頻繁的切換運行程序,反而會造成很大的壓力。

3. IO多路復用/事件驅動

技術分享圖片

小紅旗老板升級了系統,放棄使用點菜機,改用麥當勞那種點餐大屏。同樣是點餐,但是一個大屏裏面顯示了很多人的臭豆腐進度,即節省了資源,也避免大家不停的詢問。

其實Nio活著Netty就是基於這種模式,一個線程就可以監聽很多IO操作,這樣在IO等待上就高效多了。具體實現是依賴於操作系統的,windows和linux都有不同的實現方式。最初的select或者poll,都有並發數的限制,並且NIO的select還有空輪訓的問題;epool則突破了連接數的限制,一個線程就可以監聽大量的IO操作。這個感興趣的朋友,可以深入了解下select、poll、epool的原理。

4. 信號驅動IO

技術分享圖片

小紅旗老板又時髦了,搞了一個升級版的美味不用等。顧客基於微信小程序點菜,菜做好了自動提醒顧客取餐....這個提醒的過程,就像是發射了一個特殊的信號。

不過UNIX網絡編程裏面的信號驅動,可沒這麽簡單,這個信號是依賴於操作系統底層的,捕獲信號或者處理都很麻煩,所以現在應用的也不是很廣泛。

5. 異步非阻塞IO

技術分享圖片

一對小情侶李雷和韓梅梅,韓梅梅口味很重,特別喜歡吃臭豆腐,但是李雷完全不感興趣,聞到味道就想吐。於是李雷就跟韓梅梅約定,讓韓梅梅自己去吃,李雷跑到旁邊的咖啡廳喝咖啡。韓梅梅自己去排隊買臭豆腐,買完順便吃完,然後回來找李雷....

這個過程就是異步非阻塞的,消息的等待和處理都在服務器端完成,用戶只要最後接收到消息處理完的通知就行了。

總結

技術分享圖片

總結來說,這幾種網絡模型:

  1. 同步阻塞:強調的是我要做! —— 別的啥也別說,就是要做!
  2. 同步非阻塞:強調的是我想做! —— 在想的過程中,幹點其他的事情更好。
  3. 異步非阻塞:強調的是我做完了!—— 等得到結果通知的時候,工作已經做完了。

其中細節,還需慢慢體會...後面的文章將會挑幾個模型做代碼的演示,更多內容還請持續關註。

參考

  1. 並發編程網
  2. Netty源碼分析
  3. Netty源碼分析
  4. Netty源碼分析
  5. IO多路復用之select、poll、epoll
  6. 聊聊Linux五種IO模型
  7. 聊聊同步、異步、阻塞、非阻塞
  8. Netty官方文檔
  9. 一篇文章,讀懂Netty的高性能架構之道
  10. 代碼示例分享

漫談Java IO之基礎篇