亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Netty學(xué)習(xí)之理解selector原理示例

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

BIO的弊端

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

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

對(duì)應(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ù),阻塞方法,沒(méi)有數(shù)據(jù)可讀時(shí)就阻塞
            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) {
        }
    }
}

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

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

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

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

解決思路

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

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

客戶只會(huì)因?yàn)榇暝鑾煾刀荚诖暝瓒却?,而不是因?yàn)榇暝鑾煾刀荚谏档榷却?/p>

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

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

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

epoll

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

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

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

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

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

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

NIO

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

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

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

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

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

總結(jié)

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

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

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

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

相關(guān)文章

  • JAVA防止重復(fù)提交Web表單的方法

    JAVA防止重復(fù)提交Web表單的方法

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

    Java開發(fā)學(xué)習(xí) Eclipse項(xiàng)目有紅感嘆號(hào)解決之道

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

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

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

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

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

    java多線程之Phaser的使用詳解

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

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

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

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

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

    springBoot @Enable* 注解的使用

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

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

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

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

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

最新評(píng)論