談談傳統BIO網路編程模型的局限性與NIO
先來看看我們的server端:
創建一個serversocket,進行監聽,每來一個客戶端,就啟動一個新啟動為其服務:
private void createListenSocket() {
//如果創建監聽socket的時候發生異常,將會隔WAIT_TIME毫秒重試,直到成功
while (true){
try {
serverSocket = new ServerSocket(LISTEN_PORT);
Log.info(創建監聽socket成功,正在監聽...);
break;
} catch (IOException e) {
Log.error(創建監聽socket失敗,原因: e.getMessage() WAIT_TIME ms後重建);
ThreadUtils.sleep(WAIT_TIME);
}
}
}
private void listen() throws IOException {
Socket socket = null;
//啟動一個死循環來監聽連接本伺服器的socket
while ((socket = server.accept()) != null) {
// 來訪客戶記錄到伺服器:
Destination destination = new Destination();
destination.setSocket(socket);
server.newDestination(destination);
//啟動一條子線程來處理連接本伺服器的socket消息收發
new SubListenThread(destination,server).start();
}
}
以上代碼來自我半年前編寫的一個遠控程序服務端。在這個模型當中,服務端線程與客戶端線程是1:1的關係,也就是說有多少個客戶端,服務端就得創建多少個線程。
在java當中,創建線程的代價是很大的。如果有幾千個客戶端,這個程序是撐不住的。
那麼像旺旺這種在線量可以達到幾百萬的應用,在單個機器上,勢必要用一種比BIO更好的編程模型來實現。
那麼NIO就可以解決這種應用場景。
關於NIO的教程,網上有非常多的詳細教程,在這裡就不贅述。就簡單說說NIO編程模型:
首先,我們有幾個基本概念:
1.channel 大家可以把它想像成stream,只不過我們可以通過channel進行雙工通信,也就是能讀又能寫。
2.buffer 可以看做是一段緩存,我們能通過這麼一段緩存對channel進行讀寫。
3.selector 中文直接翻譯過來就是選擇器,因為在NIO當中,我們不通過傳統的一個線程處理一個客戶端,而是通過輪詢的方式知道哪些客戶端可讀、可連接,從而實現1:n的模型。
那麼NIO的編程模型如下:
通過一個selector,客戶端會連接到這個selector,我們可以通過一個死循環不斷地輪詢selector有哪些客戶端,然後一旦監聽到可讀或者可連接事件,我們就進行相應的業務邏輯處理,該讀讀,該寫寫。
以下為一個簡單多人聊天室部分源碼:
看起來還是很複雜的,至少比傳統的BIO通信模型複雜。
使用原生的nio api進行編程很難,而且這玩意還有bug,據說在1.8以上版本仍存在空輪詢BUG,會讓CPU飆到100%。
所以說,如果可以的話,盡量使用一些第三方框架,比如netty。
※剖析Hadoop和Spark的Shuffle過程差異
※30秒了解Excel的前世今生
TAG:千鋒JAVA開發學院 |