Java NIOについて


Javaの既存IOとNew IOについて説明しましょう.
昔はIOはJavaが遅い印象だったので無ブロックIO APIが提供されているため、Javaはこれらの問題を克服してきました.まず、ブロックと無ブロックから始めましょう.

Blocking, Non-Blocking


サーバの学習では、非同期非ブロックIOについてよく言及されます.NodeJSの利点は,イベントベースの非同期ブロックIOをサポートし,リソースを効率的に利用できることである.この部分も改めて説明します

Blocking API


Blocking APIとは、APIを呼び出すThreadが、API操作が完了するまで他の操作を実行しないAPIを意味する.
通常,我々が使用するJavaの基本IO関連APIはロック方式で使用される.
InputStream, OutputStream을 확장하거나 직접 사용하는 클래스들이 대표적인 예입니다.

InputStream inputstream = new FileInputStream("c:\\data\\input-text.txt");

int data = inputstream.read(); // Blocking!
while(data != -1) {
  doSomethingWithData(data);
  data = inputstream.read();
}
inputstream.close();
上記のコードに示すように、Blocking APIは、戻り値が受信される前に(動作終了時に)ロックされるため、Threadはアイドル状態のままとなる.例えば、ファイルIOに大きな遅延がなくても、CPUサイクルよりも長いため、ネットワークIOはボトルネックになりやすい.
これらの問題を解決するには、Non-Blocking APIを使用する必要があります.

Non Blocking API


簡単に言えば、Non−Blocking APIは、APIを呼び出すときに要求される動作が完了するかどうかにかかわらず、現在の状態に対する即時応答である.これは、API呼び出し後にThread制御権があるため、他の操作を実行することができるからである.
Javaの新しいIO(NIO)の出現はJavaにNon Blockingを実現させることができる.
1つのThreadはIO動作に依存しないので、1つのThreadは複数のIOを処理することができる.
APIが完了した後、どこで処理されたかによって、AsyncronousSynchronousに分けられる.
これらの概念は、パフォーマンスに直接関係するため、多くのアプリケーションで非常に重要です.
たとえば、クライアント側アプリケーションを開発する際には、外部API要求がUI Threadのロードに干渉しないように、サブミクロ非ブロック方法を理解する必要があります.
Java NIOとIOについて簡単に説明しましょう

NIOとIOの主な違い


NIOとIOは概念的にBlockingとNon-Blockingの違いがあるが,それらにも違いがある.
比較する要素は次の3つです.
  • Stream Oriented vs Buffer Oriented
  • Blocking IO vs Non Blocking IO
  • Selector
  • StreamベースとBufferベース


    Java NIOとIOの最大の違いは、IOがStreamに基づいており、NIOがBufferに基づいていることです.
    これは次のことを意味します.
    ストリームベースのJava IOは、ストリームから1回に複数のバイトを読み出す.読む内容はユーザーによって異なります.データはどこにもキャッシュされません.また、データ・ストリームを前後に移動することはできません.ストリームから読み込まれたデータを前後に移動する必要がある場合は、バッファを作成してキャッシュする必要があります.
    バッファベースのJava NIOは、わずかに異なる.処理されたバッファからデータを読み込みます.必要に応じて、バッファ内を前後に移動できます.これらの特性は、データの処理においてより柔軟性を提供します.
    ただし、バッファに必要なすべてのデータが存在するかどうかを確認して、データの整合性を確保する必要があります.
    バッファからより多くのデータを読み込む場合は、バッファに前処理されていないデータが使用されていないことを確認します.(そのためflush()が必要)

    Blocking vs Non-blocking IO


    Java IOの様々なストリームはロックされています.スレッドにread()またはwrite()が発生すると、データの読み取りまたは書き込みまでスレッドがブロックされます.詰まっている.
    Java NIOのNon-Blockingモードでは、スレッドがチャネルを介してデータを読み取り、現在使用可能なデータのみを取得できます.使用可能なデータがない場合は、すぐにデータを返さない操作を実行できます.(ネジがロックされていません.)
    この場合、threadは、データが読み取り可能になるまでブロック状態を維持するのではなく、他の操作を実行することができる.
    ブロッキングなし書き込みも同様です.threadはchannelを介してデータが書き込まれるのを待つことはなく、データがすべて書き込まれるのを待つこともありません.作成すると、スレッドはすぐに他の操作を実行できます.
    スレッドがブロックされていないIOを呼び出すと、主に他のチャネルでIOが実行されます.この点,単一スレッドは複数の入出力チャネルを管理できる.

    Selector


    Java NIOセレクタを使用すると、1つのスレッドで複数の入力チャネルを監視できます.この機能の利点は、複数のThreadを使用してIOを管理する方法と比較して、Thread切替を低減することである.
    1つのセレクタを使用して複数のチャネルを登録したり、1つのスレッドを選択して入力されたチャネルを処理したり、書き込みの準備ができているチャネルを選択したりすることができます.
    このセレクタメカニズムにより、1つのスレッドが複数のチャネルを容易に管理できます.

    NIOとIOがアプリケーション設計に与える影響


    IOキットを使用してNIOまたはIOを選択すると、アプリケーション設計の次の点に影響します.
  • The API calls to the NIO or IO classes.
  • The Processing of data
  • The number of thread used to process the data
  • API Calls


    もちろん,IOを使用する場合のAPIとNIOを使用する場合のAPIは明らかに異なる.InputStreamからは、バッファからはなくバイトデータが読み出される.

    The Processing of Data


    IOを使用する場合、InputStreamまたはReaderからバイトを読み出します.
    動作単位での文字列データストリームの処理を想定する.
    InputStream input = ...; // get the inputstream from the client socket
    BufferedReader reader = new BufferedReader(new InputStreamReader(input));
    String nameLine = reader.readLine();
    String ageLine = reader.readLine();
    String emailLine = reader.readLine();
    String PhoneLine = reader.readLine();
    処理ステータスは、プログラムがどのくらい実行されたかによって異なります.言い換えれば
    最初の読者.readLine()メソッドが返されると、テキストのローが読み込まれていることがわかります.
    readLine()が1行読み終わるまでブロックされているからです.

    NIOの実現はやや異なる.
    ByteBuffer buffer = ByteBuffer.allocate(48);
    int bytesRead = inChannel.read(buffer);
    だから、バッファに十分なデータがあることをどうやって知るのでしょうか.恐らくそうはいかない.解決策は、バッファ内のデータを表示することです.したがって、バッファ内のデータを分析する必要がある場合があります.
    この方式は効率が低く,プログラム設計の観点から複雑になる.
    ByteBuffer buffer = ByteBuffer.allocate(48);
    int bytesRead = inChannel.read(buffer);
    while(!bufferFull(bytesRead)) {
    	bytesRead = inChannel.read(buffer);
    }
    ここで、bufferFull()メソッドは、バッファ内のどれだけのデータが読み取られるかを追跡します.次に、バッファが満たされているかどうかに応じてtrue or falseを返します.バッファがデータを処理する準備ができている場合は、バッファがいっぱいです.
    バッファがいっぱいになった場合、バッファは処理されます.満たされていない場合は部分的に処理できますが、どのデータがあっても部分的に処理できます.△ほとんどの場合、そうではありません.
    is-data-in-buffer-ready loopを可視化します.以下に示します.

    サマリ


    NIOでは、1つのスレッドを使用して複数のチャネルを管理できます.ただし、ストリームをブロックしてデータを読み出すよりも、処理データが複雑になる場合があります.
    少量のデータを送信するたびに数千の接続を同時に管理する必要がある場合は、chat server、NIOを使用してサーバを実装する方が有利です.
    同様に、別のコンピュータと複数のオープン接続を維持する必要がある場合は、外部接続を1つのスレッドとして管理するとより便利です.
    1つのスレッド、複数の接続設計は、次の図を描くことができます.

    逆に、高帯域幅接続が少ない場合(大量のデータを一度に送信)は、Classic IOサーバを実装するのが適切かもしれません.次はClassic IO Server Diagramです.

    ソース


  • http://tutorials.jenkov.com/java-nio/nio-vs-io.html#main-differences-between-java-nio-and-io

  • https://velog.io/@jihoson94/BIO-vs-NIO