1. 程式人生 > >Java中的NIO非阻塞程式設計

Java中的NIO非阻塞程式設計

平時工作中用到的IO主要是java.io包中的操作,比較少用到java.nio包中操作,最近遇到的比較多對效能要求較高的應用問題,查詢了一些資料整理記錄一下,方便以後檢視。
在JDK1.4以前,Java的IO操作集中在java.io這個包中,是基於流的阻塞API。對於大多數應用來說,這樣的API使用很方便,然而,一些對效能要求較高的應用,尤其是服務端應用,往往需要一個更為有效的方式來處理IO。從JDK1.5開始,NIO API作為一個基於快取區,並能提供非阻塞IO操作的API被引入。
NIO所在的包為java.nio,其中的n表示non-blocking。但實際上我們可以把它理解為nio=new+io,因為NIO包實現了網路通訊和I/O的聯合功能,並將它們的結合發揮到極致,實現完美的網路非阻塞通訊功能。
NIO結構圖

  • NIO引入:分析普通Socket通訊中存在的I/O問題——阻塞通訊,並分析傳統的解決方法——執行緒池的優缺點,進而引入NIO解決方案:
    ①基於Socket通訊存在的問題:I/O阻塞通訊。
    在介紹NIO之前,先了解傳統I/O操作的方式。以網路應用為例,下圖描述了一個典型的網路伺服器結構的通訊過程:
    傳統網路IO操作過程
    橢圓形內的操作會迴圈進行,並且監聽連線、讀取資料、寫入資料的操作都是阻塞的。在ServerSocket類的生存期中,其重要功能如下:

  • 首先建立ServerSocket:

    //啟動服務端:
    ServerSocket server= new ServerSocket(12345
);
  • 然後接受新的連線請求:
//監聽客戶端
   while(true){
   Socket socket = server.accept();   //阻塞監聽
   }

對accept()的呼叫將一直阻塞,直到ServerSocket接受到一個連線請求為止。一旦請求連線被接受,伺服器可以讀取客戶Socket中的輸入/輸出資料,在讀取呼叫時也會阻塞。下面的程式碼演示了這個過程:

//輸入輸出流
BufferReader is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter os = new
PrintWriter(socket.getOutputStream()); //讀取資料 String line;//垃圾字串 while((line=is.readLine())!=null){//讀阻塞 //回覆資料 os.println(line);//寫阻塞 os.flush(); }

在監聽的位置accept()會被阻塞,並且在讀寫客戶端資料時也會阻塞。因此這樣的操作共造成了3個問題:
a、accept()方法的呼叫將造成阻塞,直到ServerSocket接受到一個連線請求位置;
b、BufferedReader類的readLine()方法在其快取區未滿時將會造成執行緒阻塞,只有資料足夠填滿快取區或者客戶端關閉了套接字時,方法才會返回。
c、產生大量的String垃圾,BufferedReader建立了快取區從客戶套接字讀入資料,但是同樣建立了一些字串儲存這些資料。雖然BufferedReader內部提供了StringBuffer處理,但是所有的String很快變成了垃圾需要回收,同樣的問題在傳送訊息程式碼中也存在。
其中第一個問題是ServerSocket造成的阻塞,第二個問題是BufferedReader快取造成的阻塞,第三個問題是String造成的垃圾。因此,以上的問題是Java I/O和Java網路通訊共同造成的。
②傳統的解決方法:使用執行緒池。
在JDK 1.4之前,自由使用執行緒池是處理阻塞問題最典型的辦法。面對大量的客戶端的請求,需要使用大量的執行緒,這時一般是實現一個執行緒池來處理請求,如圖:
執行緒池方式處理
使用執行緒池的方法是:在服務端啟動時建立執行緒池,當監聽到客戶端連線時,就為客戶端建立一個執行緒,並將該執行緒放入執行緒池中即可。這樣在該客戶斷開連線時,該客戶端的處理執行緒就會被歸還到執行緒池中,以提高執行緒的池化管理,提高執行緒的使用效率。例項程式碼如下:

public class TestThreadPool{
    public static void main(String args[]){
        boolean flag = true;
        try{
            //建立執行緒池
            ExecutorService pool = Executors.newFixedThreadPool(10);
            //啟動伺服器
            ServerSocket server = new ServerSocket(12345);
            System.out.println("開始監聽");
            while(true){
                //接受客戶端連線
                Socket socket = server.accept();
                //為客戶端建立一個獨立執行緒
                pool.execute(new ServiceThread(socket));
            }
            //關閉
            server.close();
            pool.shutdown();
        }catch(IoException e){
            e.printStackTrace();
        }
    }
}

執行緒池使伺服器可以處理多個連線,但是它們也同樣引發了許多問題。每個執行緒擁有自己的棧空間並且佔用一些CPU時間,耗費很大,而且很多時間是浪費在阻塞的IO操作上,沒有有效利用CPU。
③最新的解決方案:NIO非阻塞通訊。
從上面的分析可以看出,採用執行緒池的解決方法也會產生它自己的問題——執行緒開銷,執行緒開銷同時也影響效能和可伸縮性。不過,隨著NIO的到來,一切都改變了。
NIO的非阻塞IO機制是圍繞選擇器和通道構建的。Channel類表示伺服器和客戶機直接的一種通訊機制。與反應器模式一致,Selector類是Channel的多路複用器。Selector類將傳入客戶機請求多路分用,並將它們分派到各自的請求處理程式,實現對客戶端請求事件的非阻塞監聽,如下圖:
NIO通訊過程
在橢圓形區域中,Selector監聽器負責輪循客戶端的連線、讀取和寫入事件,這些事件的執行都不會被阻塞。並且為了提高執行的效率,NIO在讀取和寫入的資料中使用了快取區。

相關推薦

JavaNIO阻塞程式設計

平時工作中用到的IO主要是java.io包中的操作,比較少用到java.nio包中操作,最近遇到的比較多對效能要求較高的應用問題,查詢了一些資料整理記錄一下,方便以後檢視。 在JDK1.4以前,Java的IO操作集中在java.io這個包中,是基於流的阻塞AP

java NIO阻塞方式的Socket程式設計

1.非阻塞方式的Socket程式設計: 傳統阻塞方式的Socket程式設計,在讀取或者寫入資料時,TCP程式會阻塞直到客戶端和服務端成功連線,UDP程式會阻塞直到讀取到資料或寫入資料。阻塞方式會影響程式效能,JDK5之後的NIO引入了非阻塞方式的Socket程式設計,非

JavaNIO阻塞模式和傳統的IO的阻塞模式線上程的資源消耗

       java中的NIO對於需要IO操作的程式來說,大大的提高了效率,但從NIO的實現模式來看(底層select的遍歷),因為其非阻塞的特性,犧牲了更多的系統資源,充分利用了硬體資源。      在java的網路程式設計中,少不了執行緒操作。那麼這兩種模式對系統的消耗

Java網路程式設計 -- NIO阻塞網路程式設計

從Java1.4開始,為了替代Java IO和網路相關的API,提高程式的執行速度,Java提供了新的IO操作非阻塞的API即Java NIO。NIO中有三大核心元件:Buffer(緩衝區),Channel(通道),Selector(選擇器)。NIO基於Channel(通道)和Buffer(緩衝區))進行操

Java網路程式設計--NIO阻塞網路程式設計

從Java1.4開始,為了替代Java IO和網路相關的API,提高程式的執行速度,Java提供了新的IO操作非阻塞的API即Ja

Java異步阻塞IO NIO使用與代碼分析

package mes 127.0.0.1 back 之一 write throwable private 建立 [TOC] Java異步非阻塞IO NIO使用與代碼分析 TimeServer程序的NIO實現完整代碼 TimeServer程序來自書本《Netty權威指南》

Java NIO 阻塞socket通訊案例

NIO的特性:它以塊為基本單位處理資料,所有的資料都要通過緩衝區(Buffer)來進行傳輸。它有一個用來作為原始I/O操作的抽象通道(Channel)並提供了Selector的非同步網路介面。且支援將檔案對映到記憶體,以大幅提高I/O效率。 緩衝區中有3個重要

Java NIO-阻塞通訊

NIO(Non-block IO)指非阻塞通訊,相對於其程式設計的複雜性,通常客戶端並不需要使用非阻塞通訊以提高效能,故這裡只有服務端使用非阻塞通訊方式實現 客戶端: package com.test.client; import java.io.DataInputSt

javaNIO程式設計另一種實現超實用

  除了普通的Socket與ServerSocket實現的阻塞式通訊外,Java提供了非阻塞式通訊的NIO API。先看一下NIO的實現原理。        從圖中可以看出,伺服器上所有Channel(包括ServerSocketChannel和SocketCha

理解JAVA nio阻塞

這幾天在看JAVA nio相關的東西,網上資料說nio是非阻塞的,我實在理解不到這句話的意思; 比如我用nio來複制檔案,那一句程式碼表示非阻塞呢?我冥思苦想,實在想不出。 public static void main(String[] args) throws Exc

深入理解Java的底層阻塞原理及實現

更多 安全 posix pla static events time() 方便 原理 談到阻塞,相信大家都不會陌生了。阻塞的應用場景真的多得不要不要的,比如 生產-消費模式,限流統計等等。什麽 ArrayBlockingQueue、 LinkedBlockingQueue、

scala通過akka的actor實現socket http server(NIO阻塞模式)

1首先是sbt需要匯入的依賴 name := "HttpServer" version := "1.0" scalaVersion := "2.11.8" libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-act

第58節:Java的圖形介面程式設計-GUI

歡迎到我的簡書檢視我的文集 前言: GUI是圖形使用者介面,在Java中,圖形使用者介面我們用GUI表示,而GUI的完整英文為: Graphical User Interface(圖形使用者介面), 所謂圖形使用者介面就是以圖形的方式來顯示你計算機的操作介面, 我們計算機中操作的介面就是 我

JavaNIO,BIO,AIO釋義

一、概念         首先看下同步與非同步的區別: 同步:傳送一個請求,後臺立即處理,並返回處理結果。 非同步:傳送一個請求,不去管是否真正立即處理,可能返回的只是一個狀態值,真正的處理還並未完成。完成後非同步回撥通知或者定時去查詢結果 比

Java的流式程式設計

!!!!!!!!!注意:這個特效是在Java8之後才引進的  就是說 jdk8之前是沒有的 一. 基本概念 1.1 為什麼加入 集合的流式操作              

Java FP: Java函數語言程式設計的Map和Fold(Reduce)

原文連結 作者:  Cyrille Martraire  譯者: 李璟([email protected]) 在函數語言程式設計中,Map和Fold是兩個非常有用的操作,它們存在於每一個函數語言程式設計語言中。既然Map和Fold操作如此強大和重要,但是Java語言缺乏Map和Fol

Java FP: Java函數語言程式設計的謂詞函式(Predicates)第一部分

原文連結 作者:  Cyrille Martraire  譯者: 李璟([email protected]) 你一直在聽說函數語言程式設計將稱霸整個程式設計屆,而自己仍然沉浸在普通的Java裡?請不要擔心,因為你已經在日常Java程式碼中加入了函數語言程式設計的特性。此外,函數語言程

Java FP: Java函數語言程式設計的謂詞函式(Predicates)第二部分

public Iterable<PurchaseOrder> selectOrders(Predicate<? super PurchaseOrder> condition) {     return Iterables.filter(orders, condition)

Java FP(Java8): Java函數語言程式設計的Map和Fold(Reduce)

public double totalAmount(List<Double> amounts) { double sum = 0; for(double amount : amounts) { sum += amount; } return sum

android socket連結 NIO阻塞方式

最近在研究android的推送,一開始準備自己搭建推送伺服器,並在android機上建立一個socket長連線,由於之前一直是用c++,在網上搜索一些資料後,臨時寫了一個基於NIO模式的客戶端socket連結類,測試後能使用,當然還有很多問題,沒有去修改了,因為最後發現,現