javaNio 學習筆記(一)

javaNio 學習筆記(一)

學習參考文檔:

http://tutorials.jenkov.com/java-nio/index.html

什麼是javaNio

java Nio是java new IO。是java1.4新增的API。它提供了另一種不同於標準IO的實現方式來實現IO

知其然知其所以然

爲什麼要使用java Nio?

弄懂了爲什麼要使用Java NIO也就是知道我們爲啥要學NIO了。

首先NIO出現就是提供了替代標準IO的一種IO實現方式。那麼爲什麼要替換標準IO呢?

我們來看下下面的例子:

// server
public class Bio {
    public static void main(String[] args) {
        try {
            ServerSocket server = new ServerSocket(2999);
            System.out.println("server 監聽2999端口等待客戶端連接" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant());
            Socket socket = server.accept();
            System.out.println("server 監聽2999端口等待客戶端接受數據" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant());
            // 從套接字中獲取輸入流
            InputStream inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            inputStream.read(bytes);
            System.out.println("get message from client: " + new String(bytes) + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant());

            inputStream.close();
            socket.close();
            server.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// client
public class Client {

    public static void main(String[] args) {

        try {
            // 建立連接
            System.out.println("客戶端準備連接服務器 2999端口" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant());
            Socket socket = new Socket("127.0.0.1", 2999);
            System.out.println("客戶端連接服務器 2999端口" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant());
            // 向socket寫入數據
            OutputStream outputStream = socket.getOutputStream();
            System.out.println("客戶端連接服務器開始寫入數據" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant());
            socket.getOutputStream().write("hi, be happy".getBytes("UTF-8"));
            System.out.println("客戶端連接服務器開始寫入完成" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant());
            outputStream.close();
            socket.close();
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }
}

先啓動server,然後在啓動client(爲了讓結果比較清晰建議打斷點運行),返回結果如下

// server 返回結果:
server 監聽2999端口等待客戶端連接2020-06-11T14:35:58.428Z
server 監聽2999端口等待客戶端接受數據2020-06-11T14:36:16.120Z
get message from client: hi, be happy

// client 返回結果    
客戶端準備連接服務器 2999端口2020-06-11T14:36:02.026Z
客戶端連接服務器 2999端口2020-06-11T14:36:35.664Z
客戶端連接服務器開始寫入數據2020-06-11T14:36:40.984Z
客戶端連接服務器開始寫入完成2020-06-11T14:36:42.969Z    

運行斷點的時候會發現,當server執行到server.accept()inputStream.read()的時候程序會阻塞,讓程序等待,這樣會影響執行效率。這也就是爲什麼會有NIO來替代IO。

先自己思考解決方案

如果是讓我來解決這個問題,該如何處理呢?

可以開線程,每一個線程來處理一個client的連接。這樣即使阻塞也是隻阻塞當前線程。這樣即使阻塞也只是阻塞當前線程,而不會對其他線程造成影響。當然這麼做就會消耗系統資源,因爲線程是有限的,我們不可能無限的開啓線程,若客戶端一直未連接就需要做超時處理,將線程關閉。

Java NIO是如何來做的?

這個問題可能需要等到學習完java NIO之後纔可能回答的出來。那麼下面我就開始學習Java NIO。

java NIO簡單導讀

參考上面文檔地址

  • 傳統IO是面向流的,而java NIO則是面向channelsbuffers的。數據都是從channel中讀取到buffer或者從channel中寫入buffer
  • java NIO是非阻塞IO,即不會產生上面的問題。線程可以讓channel(有的人叫通道)去讀取buffer中的數據,這個時候線程可以做其他事情。當數據程從channel讀取到buffer的時候線程在繼續處理這部分事情。對於寫也是一樣。
  • Java NIO還提供了一個selectorselector是一個對象,可以監控多個通道的事件(如:連接打開,數據到達等)。這樣可以讓單個線程監視多個channel

java NIO 基本概念

java NIO主要的核心組件如下:

  • Channels(通道、管道、頻道)
  • buffers(數據緩衝區)
  • Selector(選擇器,從導讀的概念來看感覺有點想監聽器)

當然java NIO還有一些其他組件,後面我會慢慢進行學習。

channelbuffer就可以理解潮汐車道倆頭的地點。數據可以從頻道(channel)中寫入緩衝區(buffer).

也可以從緩衝區讀取到頻道中。

主要實現的管道類型

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

核心的緩衝區

  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

選擇器

選擇器的作用就是能讓單個線程來處理多線程的事情。要使用選擇器,需要註冊頻道。然後調用它的select()方法。此方法將阻塞,直到爲其中一個已註冊通道準備好事件爲止。方法返回後,線程就可以處理這些事件。(有傳入的連接,接收到的數據等等)

這些類型後續學習中我會進行聯繫並儘量做詳細瞭解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章