日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

NIO 简介

發布時間:2024/6/21 综合教程 25 生活家
生活随笔 收集整理的這篇文章主要介紹了 NIO 简介 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上文我們描述了五中IO類型。第一種同步阻塞模型我們我們稱之為BIO(Blocking IO),

第三種IO復用模型我們稱之為NIO(Nonblocking IO)。

 上圖我們可以很容易的發現 BIO會為每個socket請求創建一個線程,而NIO可以通過一個線程處理多個請求。當然,我們可以為BIO構建一個線程池,這是一種偽異步的BIO模型。BIO和NIO最大的區別還是在阻塞上面。

阻塞主要有兩方面

等待網絡可讀寫 server.accept()
讀寫阻塞

通過觀察InputStream的Api我們可以了解到,只有在下面三種情況下,BIO才會解除阻塞

1.有數據可讀
2.可用數據已讀取完畢
3.發送空指針或者I/O異常

所以,假如我們使用BIO進行網絡消息傳遞,在網絡不穩定的情況下,一次消息的傳遞需要花費30s,那這個bio的線程就需要阻塞30秒,假如所有的線程都阻塞30s,那系統基本就不可用了。

基于上述的問題,java推出了NIO。我們先用一段代碼看看NIO的編程

public static void main(String[] args) throws Exception {
        // 打開一個ServerSocketChannel
        ServerSocketChannel socketChannel = ServerSocketChannel.open();
        socketChannel.configureBlocking(Boolean.FALSE);
        // 獲取ServerSocketChannel綁定的Socket
        ServerSocket socket = socketChannel.socket();
        // 設置ServerSocket監聽的端口
        socket.bind(new InetSocketAddress(PORT));
        System.out.println("開始等待客戶端連接");
        // 打開一個選擇器
        Selector selector = Selector.open();
        // 將ServerSocketChannel注冊到選擇器上去并監聽accept事件
        socketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            // 這里會發生阻塞,等待就緒的通道
            int select = selector.select();
            // 沒有就緒的通道則什么也不做
            if (select == 0) {
                continue;
            }
            // 獲取SelectionKeys上已經就緒的通道的集合
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            // 遍歷每一個Key
            while (iterator.hasNext()){
                SelectionKey next = iterator.next();
                if (next.isAcceptable()){
                    ServerSocketChannel channel = (ServerSocketChannel) next.channel();
                    SocketChannel socketChannel1 = channel.accept();
                    socketChannel1.register(selector,SelectionKey.OP_READ);
                }else if (next.isReadable()){
                    readDataFromSocket(next);
                }
                iterator.remove();
            }
        }
    }
    private static ByteBuffer bb = ByteBuffer.allocate(1024);
    private static void readDataFromSocket(SelectionKey next) throws IOException {
        SocketChannel sc = (SocketChannel)next.channel();
        bb.clear();
        while (sc.read(bb)>0){
            bb.flip();//
            //告知在當前位置和限制之間是否有元素
            while (bb.hasRemaining()){
                System.out.println((char) bb.get());
            }
            System.out.println();
            bb.clear();
        }
    }

java為NIO提供了全新的API,大致有以下三種

緩沖區 Buffer

一個緩沖區對象是固定數量的數據的容器,其作用是一個存儲器,或者分段運輸區,在這里數據可被存儲并在之后用于檢索。從數據結構而言,緩沖區就是一個數組,通常是一個字節數組即ByteBuffer。每一種java基本類型都有對應的緩沖區

Channel

與socket類和SeverSocket類似。NIO提供了SocketChannelServerSocketChannel,這兩個新增的通道都支持阻塞和非阻塞模式,阻塞模式使用簡單,但是性能和可靠性都不好。非阻塞模式則相反。Channel可以自由的設置阻塞對Java來說意義非常重大。試想下之前的BIO網絡編程為什么一個連接必須要對應一個線程。由于NIO的channel可以設置非阻塞模式,我們完全可以通過一個線程接受多個socket請求。

有兩點需要我們注意:

1.文件通道總是阻塞的,不能設置成非阻塞模式

2.Channel只能往Buffer中寫入

Selector

選擇器的作用是協調管理多個channel,selector定義了4種channel事件,每次channel注冊的時候都必須定義好自己關心的是哪一種事件。注冊完成后selector會一直阻塞,直到某些事件就緒。

    public static final int OP_READ = 1 << 0;
    public static final int OP_WRITE = 1 << 2;
    public static final int OP_CONNECT = 1 << 3;
    public static final int OP_ACCEPT = 1 << 4;

在了解上述三個api之后,我們再簡單分析下上述代碼

1.創建ServerSocketChannel
2.設置ServerSocketChannel為非阻塞狀態
3.監聽端口
4.將ServerSocketChannel 注冊到一個Selector
5.等待選擇接受就緒事件,一旦接收到 即可做出相應的操作

NIO的阻塞


如上圖所示,NIO其實是有阻塞的環節的。那為什么我們仍然稱NIO是同步非阻塞IO呢。這里主要涉及到一次完整的io請求是怎么進行讀寫的。

所有的系統I/O都分為兩個階段:

  等待就緒和操作。舉例來說,讀函數,分為等待系統可讀和真正的讀;同理,寫函數分為等待網卡可以寫和真正的寫。等待就緒的阻塞是不使用CPU的,是在“空等”;而真正的讀寫操作的阻塞是使用CPU的,真正在"干活",而且這個過程非常快,屬于memory copy,帶寬通常在1GB/s級別以上,可以理解為基本不耗時。

  對于BIO而言,如果TCP RecvBuffer里沒有數據,函數會一直阻塞,直到收到數據,再阻塞的讀到的數據。

  對于NIO,如果TCP RecvBuffer有數據,就把數據從網卡讀到內存,并且返回給用戶;反之則直接返回0,永遠不會阻塞。

  所以,socket主要的讀、寫、注冊和接收函數,在等待就緒階段都是非阻塞的,真正的I/O操作是同步阻塞的(消耗CPU但性能非常高)。這部分的阻塞相對于BIO而言,是可以忽略不計的。所以我們可以認為NIO是非阻塞的。

總結

以上是生活随笔為你收集整理的NIO 简介的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。