欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Netty與NIO超詳細講解

 更新時間:2022年08月01日 15:05:10   作者:kaico2018  
Netty本質(zhì)上是一個NIO的框架,適用于服務(wù)器通訊相關(guān)的多種應(yīng)用場景。底層是NIO,NIO底層是Java?IO和網(wǎng)絡(luò)IO,再往下是TCP/IP協(xié)議,下面我們跟隨文章來詳細了解

Linux下的五種I/O模型

1)阻塞I/O(blocking I/O)

2)非阻塞I/O (nonblocking I/O)

3) I/O復(fù)用(select 和poll) (I/O multiplexing)

4)信號驅(qū)動I/O (signal driven I/O (SIGIO))

5)異步I/O (asynchronous I/O (the POSIX aio_functions))

前面四種都是同步io、第五種是異步IO;

阻塞式:當(dāng)程序沒有獲取到數(shù)據(jù)的時候,整個應(yīng)用可能會產(chǎn)生阻塞,放棄了CPU執(zhí)行,無法去做其他事情。

非阻塞式:不管有沒有獲取到數(shù)據(jù),都必須立馬返回一個結(jié)果,如果沒有獲取到數(shù)據(jù)的情況下返回一個錯誤標(biāo)記,根據(jù)錯誤的標(biāo)記不斷輪詢。BIO屬于阻塞式的io操作??梢允褂枚嗑€程實現(xiàn)異步I0,同時處理多個請求。缺點:非常消耗服務(wù)器資源CPU

阻塞IO的流程

BIO屬于阻塞式的io操作。

可以使用多線程實現(xiàn)異步IO,同時處理多個請求。缺點:非常消耗服務(wù)器資源CPU

當(dāng)我們在調(diào)用一個io函數(shù)的時候,如果沒有獲取到數(shù)據(jù)的情況下,那么就會一直等待;等待的過程中會導(dǎo)致整個應(yīng)用程序一直是一個阻塞的過程,無法去做其他的實現(xiàn)。

IO復(fù)用

IO復(fù)用機制:IO實際指的就是網(wǎng)絡(luò)的IO、多路也就是多個不同的tcp連接;復(fù)用也就是指使用同一個線程合并處理多個不同的IO操作,這樣的話可以減少CPU資源。

信號驅(qū)動I/O

發(fā)出一個請求實現(xiàn)觀察監(jiān)聽,當(dāng)有數(shù)據(jù)的時候直接走我們異步回調(diào);

異步IO

異步io也就是發(fā)出請求數(shù)據(jù)之后,剩下的事情完全實現(xiàn)異步完成

同步與異步

站在多線程的角度總結(jié):

同步整個應(yīng)用代碼執(zhí)行順序是從上往下執(zhí)行 并且返回到結(jié)果;

異步:開啟多個不同的分支實現(xiàn)并行執(zhí)行 每個線程互不影響;

站在web項目角度分析

默認的情況Http請求就是一個同步形式實現(xiàn)調(diào)用 基于請求與響應(yīng),如果我們響應(yīng)非常耗時的話,會導(dǎo)致客戶端一直等待(用戶體驗非常不好)

NIO

Java的nio是在Jdk1.4版本之后推出了一套新的io方案,這種io方案對原有io做了一次性能上的升級

NIO翻譯成英文 no blocking io 簡稱為 nio 非阻塞io,不是new io。

比傳統(tǒng)的io支持了面向緩沖區(qū)、基于通道實現(xiàn)的io的方案。

BIO 與 NIO 區(qū)別:

Bio是一個阻塞式的io,它是西向與流傳輸也就是根據(jù)每個字節(jié)實現(xiàn)傳輸效率非常低,

而我們的nio是雨向與緩沖區(qū)的非阻塞邊.其中最大的亮點:運多路復(fù)用機制,

I0多路復(fù)用

多路實際上指的是多個不同的 tcp 連接。

復(fù)用:一個線程可以維護多個不同的io操作。

優(yōu)點:占用cpu資源非常小、保證線程安全問題。

IO 多路復(fù)用實現(xiàn)原理

使用一個Java案例來描述IO多路復(fù)用的思路:

public class SocketNioTcpServer {
    private static List<SocketChannel> listSocketChannel = new ArrayList<>();
    private static ByteBuffer byteBuffer = ByteBuffer.allocate(512);
    public static void main(String[] args) {
        try {
            // 1.創(chuàng)建一個ServerSocketChannel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // 2. 綁定地址
            ServerSocketChannel bind = serverSocketChannel.bind(new InetSocketAddress(8080));
            serverSocketChannel.configureBlocking(false);
            while (true) {
                SocketChannel socketChannel = serverSocketChannel.accept();
                if (socketChannel != null) {
                    socketChannel.configureBlocking(false);
                    listSocketChannel.add(socketChannel);
                }
                for (SocketChannel scl : listSocketChannel) {
                    try {
                        int read = scl.read(byteBuffer);
                        if (read > 0) {
                            byteBuffer.flip();
                            Charset charset = Charset.forName("UTF-8");
                            String receiveText = charset.newDecoder().decode
                                    (byteBuffer.asReadOnlyBuffer()).toString();
                            System.out.println("receiveText:" + receiveText);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

NIO核心組件

通道(Channel)

通常我們nio所有的操作都是通過通道開始的,所有的通道都會注冊到統(tǒng)一個選擇器(Selector)上實現(xiàn)管理,在通過選擇器將數(shù)據(jù)統(tǒng)一寫入到 buffer中。

緩沖區(qū)(Buffer)

Buffer本質(zhì)上就是一塊內(nèi)存區(qū),可以用來讀取數(shù)據(jù),也就先將數(shù)據(jù)寫入到緩沖區(qū)中、在統(tǒng)一的寫入到硬盤上。

選擇器(Selector)

Selector可以稱做為選擇器,也可以把它叫做多路復(fù)用器,可以在單線程的情況下可以去維護多個Channel,也可以去維護多個連接;

使用Java原生API實現(xiàn)NIO操作

public class NIOServer {
    /**
     * 創(chuàng)建一個選擇器
     */
    private Selector selector;
    public void initServer(int port) throws IOException {
        // 獲得一個ServerSocketChannel通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 設(shè)置通道為非阻塞
        serverSocketChannel.configureBlocking(false);
        // 將該通道對應(yīng)的ServerSocket綁定到port端口
        serverSocketChannel.bind(new InetSocketAddress(port));
        // 獲得一個通道管理器
        this.selector = Selector.open();
        // 將通道管理器和該通道綁定,并為該通道注冊SelectionKey.OP_ACCEPT事件,注冊該事件后,
        // 當(dāng)該事件到達時,selector.select()會返回,如果該事件沒到達selector.select()會一直阻塞。
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    }
    public void listen() throws IOException {
        System.out.println("服務(wù)端啟動成功!");
        // 輪詢訪問selector
        while (true) {
            // 當(dāng)注冊的事件到達時,方法返回;否則,該方法會一直阻塞
            int select = selector.select();
            if (select == 0) {
                continue;
            }
            // 獲得selector中選中的項的迭代器,選中的項為注冊的事件
            Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator();
            while (ite.hasNext()) {
                SelectionKey key = (SelectionKey) ite.next();
                // 刪除已選的key,以防重復(fù)處理
                ite.remove();

                if (key.isAcceptable()) {// 客戶端請求連接事件
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    // 獲得和客戶端連接的通道
                    SocketChannel channel = server.accept();
                    // 設(shè)置成非阻塞
                    channel.configureBlocking(false);
                    // 在和客戶端連接成功之后,為了可以接收到客戶端的信息,需要給通道設(shè)置讀的權(quán)限。
                    channel.register(this.selector, SelectionKey.OP_READ);

                } else if (key.isReadable()) {// 獲得了可讀的事件
                    read(key);
                }

            }

        }
    }
    public void read(SelectionKey key) throws IOException {
        // 服務(wù)器可讀取消息:得到事件發(fā)生的Socket通道
        SocketChannel channel = (SocketChannel) key.channel();
        // 創(chuàng)建讀取的緩沖區(qū)
        ByteBuffer buffer = ByteBuffer.allocate(512);
        channel.read(buffer);
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("服務(wù)端收到信息:" + msg);
        ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes("utf-8"));
        channel.write(outBuffer);// 將消息回送給客戶端
    }
    public static void main(String[] args) throws IOException {
        NIOServer server = new NIOServer();
        server.initServer(8000);
        server.listen();
    }
}

Redis為什么支持高并發(fā)

Redis官方?jīng)]有windows版本redis,只有l(wèi)inux版本的reids。

Redis的底層是采用nio 多路io復(fù)用機制實現(xiàn)對多個不同的連接(tcp)實現(xiàn)io的復(fù)用;能夠非常好的支持高并發(fā),同時能夠先天性支持線程安全的問題。為什么現(xiàn)場安全?因為使用一個線程維護多個不同的io操作 原理使用nio的選擇器,將多個不同的Channel統(tǒng)一交給我們的selector(選擇器管理)。

但是nio的實現(xiàn)在不同的操作系統(tǒng)上存在差別:在我們windows操作系統(tǒng)上使用 select 實現(xiàn)輪訓(xùn)機制、在linux操作系統(tǒng)使用epoll

備注:windows操作系統(tǒng)是沒有epoll

在windows操作系統(tǒng)中使用select實現(xiàn)輪訓(xùn)機制時間復(fù)雜度是為 o(n),而且這種情況也會存在空輪訓(xùn)的情況,效率非常低、其次默認對我們的輪訓(xùn)有一定限制,所以這樣的話很難支持上萬tcp連接。

所以在這時候linux操作就出現(xiàn)epoll實現(xiàn)事件驅(qū)動回調(diào)形式通知,不會存在空輪訓(xùn)的情況,只是對活躍的socket實現(xiàn)主動回調(diào),這樣的性能有很大的提升 所以時間復(fù)雜度為是o(1)

注意:windows操作系統(tǒng)沒有epoll、只有l(wèi)inux操作系統(tǒng)有。

所以為什么Nginx、redis能夠支持非常高的并發(fā) 最終都是靠的linux版本的 io 多路復(fù)用機制epoll

到此這篇關(guān)于Netty與NIO超詳細講解的文章就介紹到這了,更多相關(guān)Netty NIO內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java獲取兩個List集合的交集代碼示例

    java獲取兩個List集合的交集代碼示例

    這篇文章主要給大家介紹了關(guān)于java獲取兩個List集合交集的相關(guān)資料,我們可以使用Stream操作來對集合進行一系列的操作,其中包括求交集,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-11-11
  • Java編程實現(xiàn)多線程TCP服務(wù)器完整實例

    Java編程實現(xiàn)多線程TCP服務(wù)器完整實例

    這篇文章主要介紹了Java編程實現(xiàn)多線程TCP服務(wù)器完整實例,具有一定借鑒價值,需要的朋友可以參考下
    2018-01-01
  • Java?Web實現(xiàn)簡易圖書管理系統(tǒng)

    Java?Web實現(xiàn)簡易圖書管理系統(tǒng)

    這篇文章主要為大家詳細介紹了Java?Web實現(xiàn)簡易圖書管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • java ThreadLocal線程局部變量常用方法使用場景示例詳解

    java ThreadLocal線程局部變量常用方法使用場景示例詳解

    這篇文章主要介紹了為大家java ThreadLocal線程局部變量常用方法使用場景示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • springboot常用語法庫的基本語法

    springboot常用語法庫的基本語法

    FreeMarker 是一款?模板引擎: 即一種基于模板和要改變的數(shù)據(jù), 并用來生成輸出文本(HTML網(wǎng)頁,電子郵件,配置文件,源代碼等)的通用工具,這篇文章主要介紹了springboot常用語法庫的基本語法,需要的朋友可以參考下
    2022-12-12
  • maven項目在實踐中的構(gòu)建管理之路的方法

    maven項目在實踐中的構(gòu)建管理之路的方法

    這篇文章主要介紹了maven項目在實踐中的構(gòu)建管理之路的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-05-05
  • Mybatis中Like的三種使用解讀

    Mybatis中Like的三種使用解讀

    這篇文章主要介紹了Mybatis中Like的三種使用解讀,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • java單鏈表使用總結(jié)

    java單鏈表使用總結(jié)

    這篇文章主要為大家詳細介紹了java單鏈表使用總結(jié),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • java?數(shù)組越界判斷和獲取數(shù)組長度的實現(xiàn)方式

    java?數(shù)組越界判斷和獲取數(shù)組長度的實現(xiàn)方式

    這篇文章主要介紹了java?數(shù)組越界判斷和獲取數(shù)組長度的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • mybatis interceptor 處理查詢參數(shù)及查詢結(jié)果的實例代碼

    mybatis interceptor 處理查詢參數(shù)及查詢結(jié)果的實例代碼

    這篇文章主要介紹了mybatis interceptor 處理查詢參數(shù)及查詢結(jié)果,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-01-01

最新評論