最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文帶你搞懂java如何實現(xiàn)網(wǎng)絡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ā)網(wǎng)絡編程實現(xiàn)

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):數(shù)據(jù)的讀寫通過緩沖區(qū)進行,而不是直接通過流(Stream)。

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

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

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

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

NIO 的核心組件

1.Channel(通道)

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

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

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

數(shù)據(jù)讀寫通過 Buffer 進行。

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

3.Selector(選擇器)

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

通過多路復用機制實現(xiàn)一個線程管理多個通道。

4.SelectionKey

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

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

場景描述

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

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

服務器端代碼

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()) { // 讀取客戶端數(shù)據(jù)事件
                            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); // 從通道中讀取數(shù)據(jù)
        } 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);

            // 回寫數(shù)據(jù)到客戶端
            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ā)送數(shù)據(jù)到服務器
        String message = "Hello, NIO Server!";
        ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
        socketChannel.write(buffer);

        // 3. 接收服務器回寫的數(shù)據(jù)
        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)流的頻繁數(shù)據(jù)拷貝,提高了讀寫效率。

NIO 的局限性和改進

1.局限性

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

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

2.改進方向

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

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

適用場景和建議

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

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

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

相關文章

  • 詳解SpringBoot+Dubbo集成ELK實戰(zhàn)

    詳解SpringBoot+Dubbo集成ELK實戰(zhàn)

    這篇文章主要介紹了詳解SpringBoot+Dubbo集成ELK實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-10-10
  • Java編程Webservice指定超時時間代碼詳解

    Java編程Webservice指定超時時間代碼詳解

    這篇文章主要介紹了Java編程Webservice指定超時時間代碼詳解,簡單介紹了webservice,然后分享了通過使用JDK對Webservice的支持進行Webservice調用實現(xiàn)指定超時時間完整示例,具有一定借鑒價值,需要的朋友可以參考下。
    2017-11-11
  • java 動態(tài)增加定時任務示例

    java 動態(tài)增加定時任務示例

    本篇文章主要介紹了java 動態(tài)增加定時任務示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • springboot讀取配置文件中的參數(shù)具體步驟

    springboot讀取配置文件中的參數(shù)具體步驟

    在本篇文章里小編給大家分享了關于springboot讀取配置文件中的參數(shù)的相關知識點內容,有需要的朋友們跟著學習下。
    2019-06-06
  • Java將時間按月份分段的實現(xiàn)思路與方法

    Java將時間按月份分段的實現(xiàn)思路與方法

    這篇文章主要給大家介紹了關于Java將時間按月份分段的實現(xiàn)思路與方法,通過文中介紹的方法可以將時間分成我們想要的時間段,文中給出了詳細的實例代碼,需要的朋友可以參考下
    2021-07-07
  • 通過簡易例子講解Java回調機制

    通過簡易例子講解Java回調機制

    這篇文章主要介紹了通過簡易例子講解Java回調機制,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • 關于web項目讀取classpath下面文件的心得分享

    關于web項目讀取classpath下面文件的心得分享

    這篇文章主要介紹了關于web項目讀取classpath下面文件的心得,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 親手教你IDEA2020.3創(chuàng)建Javaweb項目的步驟詳解

    親手教你IDEA2020.3創(chuàng)建Javaweb項目的步驟詳解

    這篇文章主要介紹了IDEA2020.3創(chuàng)建Javaweb項目的步驟詳解,本文是小編手把手教你,通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-03-03
  • 徹底理解Java 中的ThreadLocal

    徹底理解Java 中的ThreadLocal

    這篇文章主要介紹了徹底理解Java 中的ThreadLocal的相關資料,需要的朋友可以參考下
    2017-07-07
  • 解決Sentinel鏈路模式規(guī)則無效問題

    解決Sentinel鏈路模式規(guī)則無效問題

    本文介紹了如何在Spring Cloud Alibaba項目中使用Sentinel鏈路流控規(guī)則,并解決規(guī)則不生效的問題,通過關閉Sentinel過濾器,可以避免重復統(tǒng)計請求
    2025-01-01

最新評論

定兴县| 滕州市| 陇西县| 德阳市| 康马县| 波密县| 通化市| 霍林郭勒市| 蒲城县| 社旗县| 新河县| 浙江省| 东阿县| 烟台市| 宿州市| 苏尼特右旗| 黑水县| 水富县| 志丹县| 偃师市| 阆中市| 宣威市| 临猗县| 德庆县| 马公市| 德江县| 廊坊市| 宜春市| 张家界市| 新竹县| 呼和浩特市| 塔河县| 华池县| 廊坊市| 全椒县| 岚皋县| 扎囊县| 塘沽区| 时尚| 澄迈县| 象州县|