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

Netty學習之理解selector原理示例

 更新時間:2023年07月13日 11:10:53   作者:pq217  
這篇文章主要為大家介紹了Netty學習之理解selector原理示例使用分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>

BIO的弊端

BIO既是Blocking IO,也叫同步阻塞模型,BIO模型如下

如果所示,多個客戶端連接一個服務(wù)端, 每出現(xiàn)一個客戶端就開一個handler(一般對應(yīng)一個線程)處理

對應(yīng)的服務(wù)端代碼如下

public class BioServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9000);
        // 任務(wù)處理線程池
        ExecutorService pool = Executors.newFixedThreadPool(10);
        while (true) {
            System.out.println("server start");
            //阻塞方法等待客戶端連接
            Socket clientSocket = serverSocket.accept();
            System.out.println("new client");
            pool.execute(()->{
                handler(clientSocket);
            });
        }
    }
    private static void handler(Socket clientSocket) {
        try {
            byte[] bytes = new byte[1024];
            System.out.println("reading");
            //接收客戶端的數(shù)據(jù),阻塞方法,沒有數(shù)據(jù)可讀時就阻塞
            int read = clientSocket.getInputStream().read(bytes);
            System.out.println("read over");
            if (read != -1) {
                System.out.println("received data:" + new String(bytes, 0, read));
            }
            clientSocket.getOutputStream().write("HelloClient".getBytes());
            clientSocket.getOutputStream().flush();
        } catch (Exception e) {
        }
    }
}

上面的代碼使用了線程池來處理客戶端業(yè)務(wù),整個代碼有兩步阻塞

  • 一步主線程阻塞等待客戶端連接
  • 一步線程池的線程阻塞等待客戶端傳輸數(shù)據(jù)準備好

其實第一步阻塞到?jīng)]什么,作為一個服務(wù)沒有客戶的情況下不阻塞也無事可做,主要是第二個阻塞,上面代碼線程池size是10,假如當前有10個客戶端連接都不發(fā)送數(shù)據(jù),那么10個線程都阻塞,此時再來一個客戶端發(fā)送完數(shù)據(jù)也無法及時處理

假設(shè)現(xiàn)在有個澡堂子,一共雇傭10個搓澡工,BIO就好比來一個客人就分配一個搓澡師傅,這個師傅就死死盯著客人洗澡,啥時候洗澡完了就開始安排搓澡,如果十個客戶在池子里洗澡洗不完,這時有11號客戶來了,沒有空閑的搓澡師傅(都在等待客戶洗完澡),那這個客戶只能傻傻的等著,實際上十個搓澡工都沒有實際干活,但卻處于傻傻的等待不可用狀態(tài)

解決思路

通過上面的例子可以看出,BIO的模型明顯是反人類的,合理的工作流程是這樣

10個搓澡師傅都待著,什么時候有人洗完澡了才分配搓澡師傅進行搓澡,這樣搓澡師傅的工作更加合理,充分的壓榨了搓澡師傅

客戶只會因為搓澡師傅都在搓澡而等待,而不是因為搓澡師傅都在傻等而等待

這樣設(shè)計顯然更加合理,也更加符合現(xiàn)實的工作流程,相當于事件驅(qū)動,當發(fā)生洗完澡(接收到數(shù)據(jù))事件后,再安排搓澡工(線程)進行處理

回到代碼怎么才能做到以事件驅(qū)動吶?更確切的說,作為java代碼,如何得知數(shù)據(jù)傳輸?shù)氖录l(fā)生吶?

顯然java本身肯定是做不到的,我們可以想一下數(shù)據(jù)的來源,一個網(wǎng)絡(luò)數(shù)據(jù)的傳輸,一臺機器通過網(wǎng)線或無線等形式發(fā)送二進制數(shù)據(jù)到一臺電腦,硬件的驅(qū)動必然能感知到,那么操作系統(tǒng)也一定能感知到,所以一個鏈接是否有數(shù)據(jù)傳輸,操作系統(tǒng)最知道!

epoll

linux 提供了epoll系列函數(shù)

上層代碼可以通過調(diào)用該系列函數(shù)訂閱感興趣的事件,后續(xù)即可感知到注冊事件的發(fā)生,主要方法如下

  • epoll_create: 創(chuàng)建一個epoll實例
  • epoll_ctl: 訂閱事件
  • epoll_wait: 阻塞等待訂閱事件的發(fā)生

有個這系列函數(shù),java代碼就可以:

  • 調(diào)用epoll_create創(chuàng)建一個epoll實例
  • 調(diào)用epoll_ctl訂閱可讀事件(相當于有數(shù)據(jù)傳輸事件)
  • 調(diào)用epoll_wait阻塞并等待時間發(fā)生

當然不能直接調(diào)用,而是調(diào)用底層C++再調(diào)用linux函數(shù)

NIO

有了操作系統(tǒng)的支持,java就可以實現(xiàn)一個不阻塞的IO服務(wù),這就是NIO模型(Non Blocking IO)

JDK1.4開始引入java.nio包,在linux系統(tǒng)中底層就是使用epoll實現(xiàn)的(windows中基于winsock2,不開源)

先看一下NIO實現(xiàn)服務(wù)的代碼

public class NioServer {
    public static void main(String[] args) throws IOException, InterruptedException {
        // 創(chuàng)建NIO ServerSocketChannel
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(9000));
        serverSocket.configureBlocking(false);
        // 打開Selector處理Channel,底層調(diào)用epoll_create
        Selector selector = Selector.open();
        // 把ServerSocketChannel注冊到selector上,并且selector對客戶端accept連接操作感興趣,底層調(diào)用epoll_ctl
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服務(wù)啟動成功");
        while (true) {
            // 阻塞等待需要處理的事件發(fā)生,即調(diào)用epoll_wait
            selector.select();
            // 獲取selector中注冊的全部事件的 SelectionKey 實例
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            // 遍歷SelectionKey對事件進行處理
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // 如果是OP_ACCEPT事件,則進行連接獲取和事件注冊
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    // 這里只注冊了讀事件,如果需要給客戶端發(fā)送數(shù)據(jù)可以注冊寫事件,底層調(diào)用epoll_ctl
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    System.out.println("客戶端連接成功");
                } else if (key.isReadable()) {  // 如果是OP_READ事件,則進行讀取和打印
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(128);
                    int len = socketChannel.read(byteBuffer);
                    // 如果有數(shù)據(jù),把數(shù)據(jù)打印出來
                    if (len > 0) {
                        System.out.println("接收到消息:" + new String(byteBuffer.array()));
                    } else if (len == -1) { // 如果客戶端斷開連接,關(guān)閉Socket
                        System.out.println("客戶端斷開連接");
                        socketChannel.close();
                    }
                }
                //從事件集合里刪除本次處理的key,防止下次select重復處理
                iterator.remove();
            }
        }
    }
}

上面及是一個典型的NIO代碼,其中(liunx中):

  • Selector.open() 底層調(diào)用liunx的epoll_create
  • socketChannel.register(selector, SelectionKey.OP_READ)相當于調(diào)用liunx的epoll_ctl(實際上只是緩存起來,下一步再真正執(zhí)行epoll_ctl)
  • selector.select() 底層調(diào)用epoll_wait,阻塞并等待訂閱事件發(fā)生

總結(jié)

selector 是java.nio包中一個nio解決方案,主要可以實現(xiàn)

  • 訂閱IO事件,如連接事件和有數(shù)據(jù)傳輸事件
  • 阻塞并等待任何訂閱事件的發(fā)生

在linux內(nèi)核中,selector就是對epoll函數(shù)的一種封裝,或者說epoll是linux針對java selector的實現(xiàn)

以上就是Netty學習之理解selector原理示例的詳細內(nèi)容,更多關(guān)于Netty selector原理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JAVA防止重復提交Web表單的方法

    JAVA防止重復提交Web表單的方法

    這篇文章主要介紹了JAVA防止重復提交Web表單的方法,涉及Java針對表單的相關(guān)處理技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-10-10
  • Java開發(fā)學習 Eclipse項目有紅感嘆號解決之道

    Java開發(fā)學習 Eclipse項目有紅感嘆號解決之道

    這篇文章主要為大家詳細介紹了完美解決Eclipse項目有紅感嘆號問題的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 為什么Spring官方推薦的@Transational還能導致生產(chǎn)事故

    為什么Spring官方推薦的@Transational還能導致生產(chǎn)事故

    在Spring中進行事務(wù)管理非常簡單,只需要在方法上加上注解@Transactional,那么為什么Spring官方推薦的@Transational還能導致生產(chǎn)事故,本文就詳細的介紹一下
    2021-11-11
  • Java面試題之MD5加密的安全性詳解

    Java面試題之MD5加密的安全性詳解

    MD5 是 Message Digest Algorithm 的縮寫,譯為信息摘要算法,它是 Java 語言中使用很廣泛的一種加密算法。本文將通過示例討論下MD5的安全性,感興趣的可以了解一下
    2022-10-10
  • java多線程之Phaser的使用詳解

    java多線程之Phaser的使用詳解

    這篇文章主要介紹了java多線程之Phaser的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • Java實現(xiàn)從jar包中讀取指定文件的方法

    Java實現(xiàn)從jar包中讀取指定文件的方法

    這篇文章主要介紹了Java實現(xiàn)從jar包中讀取指定文件的方法,涉及java針對jar文件的讀取及查找相關(guān)操作技巧,需要的朋友可以參考下
    2017-08-08
  • Java接口操作(繼承父類并實現(xiàn)多個接口)

    Java接口操作(繼承父類并實現(xiàn)多個接口)

    這篇文章主要介紹了Java接口操作(繼承父類并實現(xiàn)多個接口),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • springBoot @Enable* 注解的使用

    springBoot @Enable* 注解的使用

    這篇文章主要介紹了springBoot @Enable* 注解的使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • Sharding Jdbc批量操作引發(fā)fullGC解決

    Sharding Jdbc批量操作引發(fā)fullGC解決

    這篇文章主要為大家介紹了Sharding Jdbc批量操作引發(fā)fullGC解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • Spring事務(wù)annotation原理詳解

    Spring事務(wù)annotation原理詳解

    這篇文章主要介紹了Spring事務(wù)annotation原理詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-02-02

最新評論