• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • Netty一:Java bio nio

    標簽: netty  nio  java  多線程

    Java支持的I/O模型

    Java共支持3種網絡編程模型/IO模式:BIO、NIO、AIO
    JavaBIO:同步并阻塞(傳統阻塞型),服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷
    JavaNIO:同步非阻塞,服務器實現模式為一個線程處理多個請求(連接),即客戶端發送的連接請求都會注冊到多路復用器上,多路復用器輪詢到連接有I/O請求就進行處理

    JavaAIO:異步非阻塞,AIO引入異步通道的概念,采用了Proactor模式,簡化了程序編寫,有效的請求才啟動線程,它的特點是先由操作系統完成后才通知服務端程序啟動線程去處理,一般適用于連接數較多且連接時間較長的應用

    BIO

    在這里插入圖片描述
    BIO(blocking I/O):同步阻塞,服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,可以通過線程池機制改善(實現多個客戶連接服務器)

    NIO

    Java NIO的非阻塞模式,使一個線程從某通道發送請求或者讀取數據,但是它僅能得到目前可用的數據,如果目前沒有數據可用時,就什么都不會獲取,而不是保持線程阻塞,所以直至數據變的可以讀取之前,該線程可以繼續做其他的事情。 非阻塞寫也是如此,一個線程請求寫入一些數據到某通道,但不需要等待它完全寫入,這個線程同時可以去做別的事情,NIO的三大核心組件Buffer,Channel,Selector

    NIO和BIO的區別

    1.BIO 以流的方式處理數據,而 NIO 以塊的方式處理數據,塊 I/O 的效率比流 I/O 高很多
    2.BIO 是阻塞的,NIO 則是非阻塞的
    3.BIO基于字節流和字符流進行操作,而 NIO 基于 Channel(通道)和 Buffer(緩沖區)進行操作,數據總是從通道讀取到緩沖區中,或者從緩沖區寫入到通道中。Selector(選擇器)用于監聽多個通道的事件(比如:連接請求,數據到達等),因此使用單個線程就可以監聽多個客戶端通道

    Buffer

    緩沖區本質上是一個可以讀寫數據的內存塊,可以理解成是一個容器對象(含數組),該對象提供了一組方法,可以更輕松地使用內存塊,,緩沖區對象內置了一些機制,能夠跟蹤和記錄緩沖區的狀態變化情況。Channel提供從文件、網絡讀取數據的渠道,但是讀取或寫入的數據都必須經由 Buffer

    Buffer類相關

    在這里插入圖片描述

    Buffer 重要屬性

    Capacity:容量,即可以容納的最大數據量;在緩沖區創建時被設定并且不能改變
    Limit:表示緩沖區的當前終點,不能對緩沖區超過極限的位置進行讀寫操作。且極限是可以修改的
    Position:位置,下一個要被讀或寫的元素的索引,每次讀寫緩沖區數據時都會改變改值,為下次讀寫作準備
    Mark:標記

    Buffer 實例代碼
    import java.nio.Buffer;
    import java.nio.IntBuffer;
    
    public class NIOBuffer {
        public static void main(String[] args){
            //創建一個Buffer
            IntBuffer intBuffer = IntBuffer.allocate(5);
            printBuffer(intBuffer);
            intBuffer.put(1);
            intBuffer.put(2);
            intBuffer.put(3);
            intBuffer.put(4);
            intBuffer.put(5);
            printBuffer(intBuffer);
            intBuffer.flip();
            printBuffer(intBuffer);
            while (intBuffer.hasRemaining()){ //表示當前位置和限制元素之間還有元素
                System.out.println(intBuffer.get());
            }
            printBuffer(intBuffer);
        }
    
        public static void printBuffer(Buffer buffer){
            System.out.println("position:"+buffer.position());
            System.out.println("limit:"+buffer.limit());
            System.out.println("capacity:"+buffer.capacity());
            System.out.println("mark:"+buffer.mark());
            System.out.println("..................... ");
        }
    }
    

    Channel

    NIO的通道類似于流,但是相比于流,通道可以同時進行讀寫數據,而流只能讀或者只能寫,通道能夠異步讀寫數據,通道可以在緩沖區中讀數據,也可以寫數據到緩沖區

    Channel類相關

    在這里插入圖片描述
    常用的 Channel 類有:FileChannel、DatagramChannel、ServerSocketChannel 和 SocketChannel。【ServerSocketChanne 類似 ServerSocket , SocketChannel 類似 Socket】。
    FileChannel 用于文件的數據讀寫,DatagramChannel 用于 UDP 的數據讀寫,ServerSocketChannel 和 SocketChannel 用于 TCP 的數據讀寫

    Channel實例代碼1
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
        public class NIOFileChannel1 {
            public static void main(String[] args) throws IOException {
                String str = "hello channel";
                FileOutputStream fileOutputStream = new FileOutputStream("E:\\Workspace\\javaiopractice\\src\\main\\resources\\data");
                //通過流獲取channel
                FileChannel fileChannel = fileOutputStream.getChannel();
                //創建一個緩沖區 ByteBuffer
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                //將str存儲到byteBuffer
                byteBuffer.put(str.getBytes());
                //對byteBuffer 進行flip
                byteBuffer.flip();
                //將byteBuffer數據寫入到fileChannel
                fileChannel.write(byteBuffer);
                fileOutputStream.close();
            }
        }
    
    Channel實例代碼2
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    public class NIOFileChannel2 {
        public static void main(String[] args) throws IOException {
            //創建文件的輸入流
            File file = new File("E:\\Workspace\\javaiopractice\\src\\main\\resources\\data");
            FileInputStream fileInputStream = new FileInputStream(file);
            //通過fileInputStream 獲取對應的FileChannel
            FileChannel fileChannel = fileInputStream.getChannel();
            //創建緩沖區
            ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());
            //將通道的數據讀入buffer
            fileChannel.read(byteBuffer);
            //將byteBuffer的數據由字節轉成string
            System.out.println(new String(byteBuffer.array()));
            fileInputStream.close();
        }
    }
    
    Channel實例3
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    public class NIOFileChannel3 {
        /**
         * 使用一個Buffer完成文件讀取
         */
        public static void main(String[] args) throws IOException {
            FileInputStream fileInputStream = new FileInputStream("1.txt");
            FileChannel fileChannel1 = fileInputStream.getChannel();
            FileOutputStream fileOutputStream = new FileOutputStream("2.txt");
            FileChannel fileChannel2 = fileOutputStream.getChannel();
            ByteBuffer byteBuffer = ByteBuffer.allocate(5);
    
            while (true){
                byteBuffer.clear(); //清空Buffer
                int read = fileChannel1.read(byteBuffer); //從channel中讀取數據到buffer
                System.out.println("read="+read);
                if(read==-1){ //讀取完成
                    break;
                }
                byteBuffer.flip();
                fileChannel2.write(byteBuffer);
            }
            //關閉相關的流
            fileInputStream.close();
            fileOutputStream.close();
    
        }
    }
    
    Channel實例4
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.channels.FileChannel;
    
    /**
     * 使用transferFrom轉換通道寫數據
     */
    public class NIOFileChannel4 {
        public static  void main(String[] args) throws IOException {
            //創建相關流
            FileInputStream fileInputStream = new FileInputStream("source.txt");
            FileOutputStream fileOutputStream = new FileOutputStream("target.txt");
            //獲取fileChannel
            FileChannel sourceChannel = fileInputStream.getChannel();
            FileChannel targetChannel = fileOutputStream.getChannel();
            //使用transferForm完成拷貝
            targetChannel.transferFrom(sourceChannel,0,sourceChannel.size());
            sourceChannel.close();
            targetChannel.close();
            fileInputStream.close();
            fileOutputStream.close();
        }
    }
    

    Selector

    Java的NIO是非阻塞的IO方式,采用Selector,可以使用一個線程來處理讀個客戶端連接,Selector 能夠檢測多個注冊的通道上是否有事件發生(注意:多個Channel以事件的方式可以注冊到同一個Selector),如果有事件發生,便獲取事件然后針對每個事件進行相應的處理。這樣就可以只用一個單線程去管理多個通道,也就是管理多個連接和請求。
    在這里插入圖片描述

    Selector相比于BIO的優勢

    1.只有在 連接/通道 真正有讀寫事件發生時,才會進行讀寫,就大大地減少了系統開銷,并且不必為每個連接都創建一個線程,不用去維護多個線程
    2.避免了多線程之間的上下文切換導致的開銷

    Selector相關類

    在這里插入圖片描述

    ServerSocketChannel類

    ServerSocketChannel在服務器端監聽新的客戶端Socket連接
    在這里插入圖片描述

    SocketChannel類

    網絡IO通道,具體負責進行讀寫操作。NIO把緩沖區的數據寫入通道,或者把通道里的數據讀到緩沖區
    在這里插入圖片描述

    AIO

    1.JDK 7 引入了 Asynchronous I/O,即 AIO。在進行 I/O 編程中,常用到兩種模式:Reactor和 Proactor。Java 的 NIO 就是 Reactor,當有事件觸發時,服務器端得到通知,進行相應的處理
    2.AIO 即 NIO2.0,叫做異步不阻塞的 IO。AIO 引入異步通道的概念,采用了 Proactor 模式,簡化了程序編寫,有效的請求才啟動線程,它的特點是先由操作系統完成后才通知服務端程序啟動線程去處理,一般適用于連接數較多且連接時間較長的應用

    版權聲明:本文為strong_yu原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/strong_yu/article/details/107928615

    智能推薦

    Linux C系統編程-線程互斥鎖(四)

    互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...

    統計學習方法 - 樸素貝葉斯

    引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...

    styled-components —— React 中的 CSS 最佳實踐

    https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...

    基于TCP/IP的網絡聊天室用Java來實現

    基于TCP/IP的網絡聊天室實現 開發工具:eclipse 開發環境:jdk1.8 發送端 接收端 工具類 運行截圖...

    猜你喜歡

    19.vue中封裝echarts組件

    19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...

    劍指Offer39-調整數組順序使奇數位于偶數前面

    一開始想著用冒泡排序的方法來做,但是bug還是很多,后來看了評論區答案,發現直接空間換時間是最簡單的,而且和快排的寫法是類似的。...

    【一只蒟蒻的刷題歷程】【藍橋杯】歷屆試題 九宮重排 (八數碼問題:BFS+集合set)

    資源限制 時間限制:1.0s 內存限制:256.0MB 問題描述 如下面第一個圖的九宮格中,放著 1~8 的數字卡片,還有一個格子空著。與空格子相鄰的格子中的卡片可以移動到空格中。經過若干次移動,可以形成第二個圖所示的局面。 我們把第一個圖的局面記為:12345678. 把第二個圖的局面記為:123.46758 顯然是按從上到下,從左到右的順序記錄數字,空格記為句點。 本題目的任務是已知九宮的初態...

    dataV組件容器寬高發生變化后,組件不會自適應解決方法

    項目中需要大屏幕數據展示,于是使用了dataV組件,但是使用是發現拖動瀏覽器邊框,dataV組件顯示異常,如圖: 于是查了官網,官網的解釋如下:   于是按照官網的意思編寫代碼: 于是可以自適應了...

    CSS3干貨10:如何做一個板塊標題水平線左邊帶顏色效果

    很多網站在設計欄目標題的時候,喜歡用下劃線分開欄目標題和內容部分。 而且線條左邊的部分往往還有顏色,且這個顏色跟標題的文字長短保持一致。效果如圖所示: 這種效果其實很簡單。 我這里給大家推薦兩種方式: 假定我們的標題部分 HTML 結構如下: 方式一:利用下邊框。灰色部分是 h1 的下邊框,藍色部分是 span 標簽的下邊框。 h1 的高度為 40px,span 也設置它的高度為 40px。這樣,...

    精品国产乱码久久久久久蜜桃不卡