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

一文帶你搞懂java如何實現網絡NIO高并發(fā)編程

 更新時間:2024年12月28日 10:10:52   作者:緣友一世  
NIO是?Java?在?JDK?1.4?中引入的一套新的?I/O?API,旨在解決傳統(tǒng)?I/O高并發(fā)場景下的性能和擴展性不足的問題,下面就跟隨小編一起深入了解下NIO高并發(fā)編程吧

Java NIO 簡介及高并發(fā)網絡編程實現

Java NIO

NIO(Non-blocking I/O,非阻塞 I/O)是 Java 在 JDK 1.4 中引入的一套新的 I/O API,旨在解決傳統(tǒng) I/O(即 BIO,阻塞 I/O)在高并發(fā)場景下的性能和擴展性不足的問題。

NIO 的核心特點

非阻塞 I/O:支持非阻塞模式,可以讓線程不必一直等待 I/O 操作完成,從而提高系統(tǒng)資源利用率。

基于緩沖區(qū)(Buffer):數據的讀寫通過緩沖區(qū)進行,而不是直接通過流(Stream)。

選擇器(Selector):通過一個線程管理多個通道(Channel),極大地提升了高并發(fā)場景下的擴展性和效率。

多路復用:通過 Selector 機制可以同時監(jiān)控多個通道的狀態(tài)(如連接就緒、讀數據就緒等)。

BIO(阻塞 I/O)與 NIO(非阻塞 I/O) 對比

特性BIONIO
I/O 模式阻塞,線程會等待 I/O 完成非阻塞,線程無需等待 I/O 完成
線程模型每個連接一個線程一個線程管理多個連接
適用場景低并發(fā)、簡單場景高并發(fā)、網絡編程場景
性能線程資源成本高,擴展性差更高效的資源利用,擴展性更好

NIO 的核心組件

1.Channel(通道)

類似流(Stream),但 Channel 同時支持讀和寫。

常見的 Channel:SocketChannel、ServerSocketChannel、DatagramChannel、FileChannel。

2.Buffer(緩沖區(qū))

數據讀寫通過 Buffer 進行。

常見的緩沖區(qū):ByteBuffer、CharBuffer、IntBuffer 等。

3.Selector(選擇器)

核心組件,用于監(jiān)聽多個通道的事件,如連接就緒、讀就緒、寫就緒等。

通過多路復用機制實現一個線程管理多個通道。

4.SelectionKey

表示通道和選擇器的注冊關系,包含通道的事件類型(如讀、寫、連接等)。

Java NIO 網絡高并發(fā)編程示例

場景描述

服務器端:監(jiān)聽客戶端請求,接收數據并返回信息。

客戶端:連接服務器,發(fā)送數據并接收響應。

服務器端代碼

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

public class NioServer {
    public static void main(String[] args) {
        try {
            // 1. 創(chuàng)建 ServerSocketChannel 用于監(jiān)聽客戶端連接
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            serverChannel.bind(new InetSocketAddress(8080));
            serverChannel.configureBlocking(false); // 設置為非阻塞模式

            // 2. 創(chuàng)建 Selector 并注冊 ServerSocketChannel,監(jiān)聽 ACCEPT 事件
            Selector selector = Selector.open();
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);

            System.out.println("NIO Server started on port 8080...");

            while (true) {
                // 3. 檢查是否有事件發(fā)生,阻塞等待
                if (selector.select() == 0) {
                    continue; // 如果沒有事件就緒,繼續(xù)循環(huán)
                }

                // 4. 獲取就緒的事件集合
                Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    keyIterator.remove(); // 移除當前處理的 key,避免重復處理

                    try {
                        // 5. 處理不同的事件
                        if (key.isAcceptable()) { // 客戶端連接事件
                            handleAccept(key, selector);
                        } else if (key.isReadable()) { // 讀取客戶端數據事件
                            handleRead(key);
                        }
                    } catch (IOException e) {
                        System.err.println("Error handling client connection: " + e.getMessage());
                        key.cancel(); // 取消出錯的鍵
                        if (key.channel() != null) {
                            key.channel().close();
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 處理 ACCEPT 事件
    private static void handleAccept(SelectionKey key, Selector selector) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
        SocketChannel clientChannel = serverChannel.accept(); // 接受客戶端連接
        clientChannel.configureBlocking(false); // 設置為非阻塞模式
        clientChannel.register(selector, SelectionKey.OP_READ); // 注冊 READ 事件
        System.out.println("Client connected: " + clientChannel.getRemoteAddress());
    }

    // 處理 READ 事件
    private static void handleRead(SelectionKey key) throws IOException {
        SocketChannel clientChannel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int bytesRead;

        try {
            bytesRead = clientChannel.read(buffer); // 從通道中讀取數據
        } catch (SocketException e) {
            System.err.println("Connection reset by client: " + clientChannel.getRemoteAddress());
            clientChannel.close();
            key.cancel();
            return;
        }

        if (bytesRead > 0) {
            buffer.flip(); // 切換到讀取模式
            String message = new String(buffer.array(), 0, buffer.limit());
            System.out.println("Received from client: " + message);

            // 回寫數據到客戶端
            buffer.clear();
            buffer.put(("Echo: " + message).getBytes());
            buffer.flip();
            clientChannel.write(buffer);
        } else if (bytesRead == -1) { // 客戶端斷開連接
            System.out.println("Client disconnected: " + clientChannel.getRemoteAddress());
            clientChannel.close();
            key.cancel(); // 取消注冊的事件
        }
    }
}

客戶端代碼

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NioClient {

    public static void main(String[] args) throws IOException {
        // 1. 創(chuàng)建 SocketChannel 連接服務器
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);

        if (!socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080))) {
            // 等待連接完成
            while (!socketChannel.finishConnect()) {
                System.out.println("Connecting to server...");
            }
        }

        System.out.println("Connected to the server");

        // 2. 發(fā)送數據到服務器
        String message = "Hello, NIO Server!";
        ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
        socketChannel.write(buffer);

        // 3. 接收服務器回寫的數據
        buffer.clear();
        int bytesRead = socketChannel.read(buffer);
        if (bytesRead > 0) {
            buffer.flip();
            String response = new String(buffer.array(), 0, buffer.limit());
            System.out.println("Received from server: " + response);
        }

        socketChannel.close();
    }
}

運行結果

客戶端輸出

 Connected to the server
 Received from server: Echo: Hello, NIO S
 進程已結束,退出代碼為 0

服務器端輸出

 NIO Server started on port 8080...
 Client connected: /127.0.0.1:50104
 Received from client: Hello, NIO Server!
 Connection reset by client: /127.0.0.1:50104

NIO 高并發(fā)的關鍵點

非阻塞 I/O:通過 Selector 一個線程可以同時監(jiān)聽多個客戶端連接,無需為每個連接創(chuàng)建一個線程,降低了線程開銷。

多路復用:Selector 提供多路復用機制,能同時監(jiān)聽多個事件(如連接就緒、讀就緒等)。

IO 操作優(yōu)化:通過 ByteBuffer 進行 I/O 操作,避免了傳統(tǒng)流的頻繁數據拷貝,提高了讀寫效率。

NIO 的局限性和改進

1.局限性

NIO 的使用相對復雜,需要手動管理通道和緩沖區(qū)。

在高并發(fā)場景下,Selector 的性能可能成為瓶頸。

2.改進方向

Netty:一個基于 NIO 的高性能網絡框架,簡化了 NIO 的使用,同時提供了更高的吞吐量和擴展性。

異步 I/O(AIO):Java NIO 2.0(JDK 7 引入)提供了異步 I/O,進一步優(yōu)化了線程資源利用。

適用場景和建議

適用場景:高并發(fā)的網絡應用,例如 Web 服務器、消息推送服務;I/O 密集型應用。

使用建議:對于復雜的高性能網絡應用,建議使用 Netty 等成熟框架,避免直接操作 NIO 的底層代碼。

以上就是一文帶你搞懂java如何實現網絡NIO高并發(fā)編程的詳細內容,更多關于java網絡NIO高并發(fā)編程的資料請關注腳本之家其它相關文章!

相關文章

  • springmvc的@Validated注解使用

    springmvc的@Validated注解使用

    這篇文章主要介紹了springmvc的@Validated注解使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • Java Spring AOP之PointCut案例詳解

    Java Spring AOP之PointCut案例詳解

    這篇文章主要介紹了Java Spring AOP之PointCut案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2021-09-09
  • Java程序初始化啟動自動執(zhí)行的三種方式

    Java程序初始化啟動自動執(zhí)行的三種方式

    這篇文章主要介紹了Java程序初始化啟動自動執(zhí)行的三種方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • java中接口(interface)及使用方法示例

    java中接口(interface)及使用方法示例

    這篇文章主要介紹了java中接口(interface)及使用方法示例,涉及接口定義的簡單介紹以及Java語言代碼示例,具有一定借鑒價值,需要的朋友可以參考下。
    2017-11-11
  • Spring實戰(zhàn)之使用c:命名空間簡化配置操作示例

    Spring實戰(zhàn)之使用c:命名空間簡化配置操作示例

    這篇文章主要介紹了Spring實戰(zhàn)之使用c:命名空間簡化配置操作,結合實例形式詳細分析了Spring使用c:命名空間簡化配置的相關接口與配置操作技巧,需要的朋友可以參考下
    2019-12-12
  • Java使用POI-TL和JFreeChart動態(tài)生成Word報告

    Java使用POI-TL和JFreeChart動態(tài)生成Word報告

    本文介紹了使用POI-TL和JFreeChart生成包含動態(tài)數據和圖表的Word報告的方法,并分享了實際開發(fā)中的踩坑經驗,通過代碼示例講解的非常詳細,具有一定的參考價值,需要的朋友可以參考下
    2025-02-02
  • 在Struts2中如何將父類屬性序列化為JSON格式的解決方法

    在Struts2中如何將父類屬性序列化為JSON格式的解決方法

    本篇文章,小編將為大家介紹關于在Struts2中如何將父類屬性序列化為JSON格式的解決方法,有需要的朋友可以參考一下
    2013-04-04
  • Java中對象的比較操作實例分析

    Java中對象的比較操作實例分析

    這篇文章主要介紹了Java中對象的比較操作,結合實例形式分析了java對象比較操作實現方法與相關操作注意事項,需要的朋友可以參考下
    2019-08-08
  • 詳解Java的類加載機制及熱部署的原理

    詳解Java的類加載機制及熱部署的原理

    今天我要講的就是Java的熱部署的原理,由于熱部署的原理和類的加載機制有關,所以打算講一下類加載的機制,文中介紹的非常詳細,需要的朋友可以參考下
    2021-05-05
  • Java多線程的調度_動力節(jié)點Java學院整理

    Java多線程的調度_動力節(jié)點Java學院整理

    有多個線程,如何控制它們執(zhí)行的先后次序呢?下文給大家分享四種方法及java多線程調度的實例代碼,需要的朋友參考下吧
    2017-05-05

最新評論