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

Java?NIO中四大核心組件的使用詳解

 更新時間:2023年05月11日 14:18:58   作者:蜀山劍客李沐白  
Java?NIO(New?IO)是Java?1.4版本中引入的一套全新的IO處理機(jī)制,而NIO提供了四個核心組件:Channel、Buffer、Selector和SelectionKey,本文就來簡單講講這四大組件的使用吧

Java NIO(New IO)是Java 1.4版本中引入的一套全新的IO處理機(jī)制,與之前的傳統(tǒng)IO相比,NIO具有更高的可擴(kuò)展性和靈活性,特別是在網(wǎng)絡(luò)編程和高并發(fā)場景下,表現(xiàn)得更為出色。

NIO提供了四個核心組件:Channel、Buffer、Selector和SelectionKey,通過它們的協(xié)同配合,實現(xiàn)數(shù)據(jù)的讀寫和同步、非同步IO操作。本文將從基礎(chǔ)概念、核心組件、使用方法等方面全面詳細(xì)地介紹Java NIO,總字?jǐn)?shù)約8000字。

一、基礎(chǔ)概念

1.1 IO和NIO的區(qū)別

Java IO和NIO的主要區(qū)別在于兩者的處理方式不同。Java IO是面向流(Stream)的,它將輸入輸出數(shù)據(jù)直接傳輸?shù)侥繕?biāo)設(shè)備或文件中,以流的形式進(jìn)行讀寫;而NIO則是面向緩沖區(qū)(Buffer)的,它將會使用緩存去管理數(shù)據(jù),使得讀寫操作更加快速和靈活。

特別是在網(wǎng)絡(luò)編程和高并發(fā)場景下,Java NIO表現(xiàn)得更為出色。Java IO在進(jìn)行網(wǎng)絡(luò)通信時,每個客戶端連接都需要創(chuàng)建一個線程來進(jìn)行處理,這樣會導(dǎo)致系統(tǒng)資源的浪費。Java NIO則只需要一個線程就可以完成對多個客戶端連接的處理,大大減少系統(tǒng)資源的占用。

1.2 緩沖區(qū)

緩沖區(qū)是Java NIO中一個非常重要的概念,它是用來存儲IO操作的數(shù)據(jù)的一段連續(xù)區(qū)域。緩沖區(qū)可以在內(nèi)存中創(chuàng)建,并可以通過通道(Channel)進(jìn)行讀寫操作,也可以作為參數(shù)傳遞給其他方法。除此之外,緩沖區(qū)還有特定的類型,例如ByteBuffer、CharBuffer、IntBuffer等。

不同類型的緩沖區(qū)都包含以下幾個基本屬性:

  • Capacity:容量,緩沖區(qū)中最多可以存儲的元素數(shù)量;
  • Position:當(dāng)前位置,下一個要被讀取或?qū)懭氲奈恢茫?/li>
  • Limit:限制,緩沖區(qū)中的限制,表示可以讀寫的元素數(shù)量;
  • Mark:標(biāo)記,可以讓緩沖區(qū)記住一個position或limit的值,通過調(diào)用reset()方法來恢復(fù)到這些值。

緩沖區(qū)的讀寫操作都會修改position和limit屬性,例如在從緩沖區(qū)中讀取數(shù)據(jù)時,position屬性會自動向后移動,而limit屬性則不會更改,因此讀取操作只能讀取到limit位置之前的數(shù)據(jù)。

1.3 通道

通道(Channel)是Java NIO中網(wǎng)絡(luò)或文件IO操作的抽象,它類似于傳統(tǒng)IO中的Stream,但是它更加靈活和高效。通道可以和緩沖區(qū)一起使用,讓數(shù)據(jù)直接在緩沖區(qū)之間進(jìn)行傳輸,可以使用Selector選擇器實現(xiàn)非阻塞IO操作。

通道主要分為以下四種類型:

  • FileChannel:用于文件讀寫操作;
  • DatagramChannel:用于UDP協(xié)議的網(wǎng)絡(luò)通信;
  • SocketChannel:用于TCP協(xié)議的網(wǎng)絡(luò)通信;
  • ServerSocketChannel:用于監(jiān)聽TCP連接請求。

在使用NIO進(jìn)行網(wǎng)絡(luò)編程時,我們常常使用SocketChannel和ServerSocketChannel來實現(xiàn)客戶端與服務(wù)器之間的通信。使用FileChannel可以完成對本地文件的讀寫操作,使用DatagramChannel可以發(fā)送和接收UDP協(xié)議的數(shù)據(jù)包。

1.4 選擇器和選擇鍵

選擇器(Selector)和選擇鍵(SelectionKey)是Java NIO提供的另外兩個核心組件。選擇器用于檢測一個或多個通道的狀態(tài),并且可以根據(jù)通道狀態(tài)進(jìn)行非阻塞選擇操作。而選擇鍵則是一種將通道和選擇器進(jìn)行關(guān)聯(lián)的機(jī)制。

使用選擇器可以實現(xiàn)單線程管理多個通道的方式,以此實現(xiàn)高并發(fā)IO操作。在選擇器的模型中,每個通道都會注冊到一個選擇器上,并且每個通道都有一個其唯一的選擇鍵對象來代表這個通道。選擇鍵對象包含幾個標(biāo)志位,表示通道的當(dāng)前狀態(tài)等信息。

選擇器可以監(jiān)聽多個通道的事件,例如連接就緒、讀取數(shù)據(jù)就緒、寫入數(shù)據(jù)就緒等等。當(dāng)有一個或多個通道的事件就緒時,選擇器就會自動返回這些通道的選擇鍵,我們可以通過選擇鍵獲取到對應(yīng)的通道,然后進(jìn)行相應(yīng)的操作。

二、核心組件

Java NIO包含了四個核心組件:Channel、Buffer、Selector和SelectionKey。下面我們將分別介紹這四個組件的作用和使用方法。

2.1 Channel

Channel是Java NIO中網(wǎng)絡(luò)通信和文件IO操作的抽象,類似于傳統(tǒng)IO中的Stream。它可以支持雙向讀寫操作,并且可以通過緩沖區(qū)來直接進(jìn)行數(shù)據(jù)讀取或?qū)懭?。通常情況下,我們會創(chuàng)建一個Channel對象,然后將其綁定到一個Socket、File、Pipe等資源上進(jìn)行讀寫操作。

NIO中主要提供了以下幾種類型的Channel:

  • FileChannel:用于文件讀寫操作;
  • DatagramChannel:用于UDP協(xié)議的網(wǎng)絡(luò)通信;
  • SocketChannel:用于TCP協(xié)議的網(wǎng)絡(luò)通信;
  • ServerSocketChannel:用于監(jiān)聽TCP連接請求。

我們可以通過調(diào)用相應(yīng)的工廠方法來創(chuàng)建不同類型的Channel。

2.1.1 FileChannel

FileChannel是Java NIO中對本地文件讀寫操作的封裝。正如其名字所示,F(xiàn)ileChannel對象是針對文件的Channel,通過FileInputStream或FileOutputStream來獲取。通過FileChannel,我們可以實現(xiàn)對文件的讀取和寫入操作,也可以使用它的position()方法來控制讀寫位置,并配合Buffer進(jìn)行數(shù)據(jù)操作。

下面是一個使用FileChannel讀取文件的例子:

public static void main(String[] args) throws IOException {
    RandomAccessFile file = new RandomAccessFile("test.txt", "rw");
    FileChannel channel = file.getChannel();
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    int bytesRead = channel.read(buffer);
    while (bytesRead != -1) {
        buffer.flip();
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        buffer.clear();
        bytesRead = channel.read(buffer);
    }
    file.close();
}

在這個例子中,我們使用FileChannel讀取一個名為test.txt的文本文件。首先,我們獲取到了一個文件對象,并通過它的getChannel()方法來獲取FileChannel對象;然后,我們創(chuàng)建一個容量為1024的ByteBuffer緩沖區(qū)來接收讀取到的數(shù)據(jù)。循環(huán)讀取數(shù)據(jù)時,我們將緩沖區(qū)的limit和position屬性進(jìn)行調(diào)整,以便緩沖區(qū)可以正常存儲和處理讀取到的數(shù)據(jù)。

2.1.2 DatagramChannel

DatagramChannel是Java NIO中對UDP協(xié)議通信的封裝。通過DatagramChannel對象,我們可以實現(xiàn)發(fā)送和接收UDP數(shù)據(jù)包。它與TCP協(xié)議不同的是,UDP協(xié)議沒有連接的概念,所以無需像SocketChannel一樣先建立連接再開始通信。

下面是一個使用DatagramChannel發(fā)送和接收UDP數(shù)據(jù)包的例子:

public static void main(String[] args) throws IOException {
    DatagramChannel channel = DatagramChannel.open();
    channel.configureBlocking(false);
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    Scanner scanner = new Scanner(System.in);
    while (scanner.hasNext()) {
        String message = scanner.next();
        buffer.put(message.getBytes());
        buffer.flip();
        channel.send(buffer, new InetSocketAddress("127.0.0.1", 8888));
        buffer.clear();
        channel.receive(buffer);
        buffer.flip();
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        buffer.clear();
    }
    channel.close();
}

在這個例子中,我們創(chuàng)建了一個DatagramChannel對象,并調(diào)用configureBlocking(false)方法將其設(shè)置為非阻塞模式。然后,通過Scanner類獲取用戶輸入的消息,將消息存放到ByteBuffer緩沖區(qū)中,并使用send()方法將其發(fā)送出去。接著,我們調(diào)用receive()方法來接收對方發(fā)送回來的消息,并將其打印到控制臺上。

2.1.3 SocketChannel

SocketChannel是Java NIO中對TCP協(xié)議通信的封裝。通過SocketChannel對象,我們可以實現(xiàn)對TCP連接的建立和通信交互。與傳統(tǒng)的Socket操作不同的是,SocketChannel基于非阻塞IO模式,可以在同一個線程內(nèi)同時管理多個通信連接,從而提高系統(tǒng)的并發(fā)處理能力。

下面是一個使用SocketChannel發(fā)送和接收TCP數(shù)據(jù)的例子:

public static void main(String[] args) throws IOException {
    SocketChannel channel = SocketChannel.open();
    channel.configureBlocking(false);
    channel.connect(new InetSocketAddress("bing.com", 80));
    while (!channel.finishConnect()) {
        // 等待連接建立完成
    }
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    String requestHeader = "GET / HTTP/1.1\r\n" +
                 "Host: www.bing.com\r\n" +
                 "Connection: Keep-Alive\r\n\r\n";
    buffer.put(requestHeader.getBytes());
    buffer.flip();
    while (buffer.hasRemaining()) {
        channel.write(buffer);
    }
    buffer.clear();
    while (channel.read(buffer) != -1) {
        buffer.flip();
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        buffer.clear();
    }
    channel.close();
}

在這個例子中,我們創(chuàng)建了一個SocketChannel對象,并調(diào)用configureBlocking(false)方法將其設(shè)置為非阻塞模式。然后,我們使用connect()方法來建立與目標(biāo)主機(jī)的TCP連接,并使用finishConnect()方法等待連接的建立完成。

接著,我們構(gòu)造了一個HTTP請求頭部,并將其存放到ByteBuffer緩沖區(qū)中,使用write()方法將其發(fā)送出去。最后,我們循環(huán)讀取SocketChannel中的數(shù)據(jù),將其打印到控制臺上。

2.1.4 ServerSocketChannel

ServerSocketChannel是Java NIO中用于監(jiān)聽TCP連接請求的封裝。通過ServerSocketChannel,我們可以監(jiān)聽來自客戶端的連接請求,并創(chuàng)建相應(yīng)的SocketChannel對象進(jìn)行通信交互。與傳統(tǒng)的ServerSocket不同的是,ServerSocketChannel基于非阻塞IO模式,可以在同一個線程內(nèi)同時管理多個客戶端連接請求,從而提高系統(tǒng)的并發(fā)處理能力。

下面是一個使用ServerSocketChannel監(jiān)聽TCP連接請求的例子:

public static void main(String[] args) throws IOException {
    ServerSocketChannel serverChannel = ServerSocketChannel.open();
    serverChannel.socket().bind(new InetSocketAddress(8888));
    serverChannel.configureBlocking(false);
    while (true) {
        SocketChannel channel = serverChannel.accept();
        if (channel != null) {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int bytesRead = channel.read(buffer);
            while (bytesRead != -1) {
                buffer.flip();
                while (buffer.hasRemaining()) {
                    System.out.print((char) buffer.get());
                }
                buffer.clear();
                bytesRead = channel.read(buffer);
            }
            channel.close();
        }
    }
}

在這個例子中,我們創(chuàng)建了一個ServerSocketChannel對象,并通過bind()方法將其綁定到本地的8888端口上。然后,我們使用configureBlocking(false)方法將其設(shè)置為非阻塞模式,并啟動一個無限循環(huán)來接收客戶端連接請求。

當(dāng)一個客戶端連接請求到達(dá)時,我們調(diào)用accept()方法來接收它,并創(chuàng)建一個與客戶端通信的SocketChannel對象。接著,我們讀取SocketChannel中的數(shù)據(jù),并將其打印到控制臺上,完成一次客戶端請求的處理。

2.2 Buffer

Buffer是Java NIO中用于存儲IO操作數(shù)據(jù)的緩沖區(qū)組件,它提供了一種更加高效、可控的數(shù)據(jù)讀寫方式。在進(jìn)行數(shù)據(jù)讀寫操作時,我們需要將數(shù)據(jù)存放到Buffer中,并且使用相應(yīng)的方法對其進(jìn)行操作。

NIO中主要提供了以下幾種類型的Buffer:

  • ByteBuffer:用于存儲字節(jié)數(shù)據(jù);
  • CharBuffer:用于存儲字符數(shù)據(jù);
  • ShortBuffer、IntBuffer、LongBuffer、FloatBuffer和DoubleBuffer:用于存儲各種基本類型數(shù)據(jù)。

使用Buffer的方式具有一定的規(guī)律性,通常情況下,我們都需要遵循以下幾個步驟:

  • 創(chuàng)建Buffer對象;
  • 存儲數(shù)據(jù)到Buffer中;
  • 調(diào)用flip()方法將Buffer從寫模式切換為讀模式;
  • 從Buffer中讀取數(shù)據(jù);
  • 調(diào)用clear()或compact()方法清空或壓縮Buffer。

下面是一個使用ByteBuffer實現(xiàn)文件讀取功能的例子:

public static void main(String[] args) throws IOException {
    FileInputStream inputStream = new FileInputStream("test.txt");
    FileChannel channel = inputStream.getChannel();
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    int bytesRead = channel.read(buffer);
    while (bytesRead != -1) {
        buffer.flip();
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        buffer.clear();
        bytesRead = channel.read(buffer);
    }
    inputStream.close();
}

在這個例子中,我們創(chuàng)建了一個ByteBuffer緩沖區(qū),并調(diào)用FileChannel的read()方法將文件中的數(shù)據(jù)讀取到緩沖區(qū)中。然后,我們調(diào)用flip()方法將緩沖區(qū)從寫模式切換為讀模式,使用get()方法逐個獲取緩沖區(qū)中的字節(jié)數(shù)據(jù),并將其轉(zhuǎn)換成字符類型輸出到控制臺上。

2.3 Selector

Selector是Java NIO中用于網(wǎng)絡(luò)通信的多路復(fù)用器組件,它可以監(jiān)控多個通道的IO操作狀態(tài),并在狀態(tài)就緒時將其返回給程序處理。使用Selector可以實現(xiàn)單線程管理多個通道的方式,以此實現(xiàn)高并發(fā)IO操作。

下面是一個使用Selector進(jìn)行TCP連接監(jiān)聽的例子:

public static void main(String[] args) throws IOException {
    Selector selector = Selector.open();
    ServerSocketChannel serverChannel = ServerSocketChannel.open();
    serverChannel.socket().bind(new InetSocketAddress(8888));
    serverChannel.configureBlocking(false);
    serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    while (true) {
        int readyCount = selector.select();
        if (readyCount == 0) {
            continue;
        }
        Set<SelectionKey> selectedKeys = selector.selectedKeys();
        Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
        while (keyIterator.hasNext()) {
            SelectionKey key = keyIterator.next();
            if (key.isAcceptable()) {
                SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
                channel.configureBlocking(false);
                channel.register(selector, SelectionKey.OP_READ);
            } else if (key.isReadable()) {
                SocketChannel channel = (SocketChannel) key.channel();
                int bytesRead = channel.read(buffer);
                while (bytesRead != -1) {
                    buffer.flip();
                    while (buffer.hasRemaining()) {
                        System.out.print((char) buffer.get());
                    }
                    buffer.clear();
                    bytesRead = channel.read(buffer);
                }
                channel.close();
            }
            keyIterator.remove();
        }
    }
}

在這個例子中,我們創(chuàng)建了一個Selector對象,并通過ServerSocketChannel的register()方法將其注冊到Selector上,監(jiān)聽其連接請求的就緒狀態(tài)。當(dāng)有新的客戶端連接請求到達(dá)時,我們調(diào)用accept()方法來接受它,并將其SocketChannel對象注冊到Selector上,監(jiān)聽其讀取數(shù)據(jù)的就緒狀態(tài)。

在進(jìn)行網(wǎng)絡(luò)通信時,如果有數(shù)據(jù)到達(dá),則Selector會檢測到其可讀性,然后調(diào)用對應(yīng)的處理方法進(jìn)行數(shù)據(jù)讀取和處理。最后,我們通過調(diào)用SelectionKey對象的remove()方法從Selector中移除監(jiān)聽鍵,以便下次可以再詳細(xì)說明一下上面的例子:

在while循環(huán)中,我們首先調(diào)用Selector的select()方法來檢測當(dāng)前是否有通道讀寫事件就緒。如果沒有就緒的事件,則select()方法會阻塞,直到有事件發(fā)生為止。

如果有事件就緒,則調(diào)用selectedKeys()方法獲取所有就緒的SelectionKey對象,并通過迭代器依次處理每個事件。

如果當(dāng)前事件是連接請求事件,我們使用ServerSocketChannel的accept()方法接受該連接請求,并將其register()到Selector上進(jìn)行監(jiān)聽讀取操作。

如果當(dāng)前事件是可讀事件,我們通過SelectionKey對象獲取對應(yīng)的SocketChannel,并從中讀取數(shù)據(jù),完成讀取后,關(guān)閉SocketChannel對象。

最后,我們通過調(diào)用SelectionKey對象的remove()方法從Selector中移除監(jiān)聽鍵,以便下次可以重新注冊。

Selector不僅可以監(jiān)聽TCP連接請求,還可以監(jiān)聽其他網(wǎng)絡(luò)事件,如可讀、可寫等。通過Selector的多路復(fù)用機(jī)制,我們可以在單線程內(nèi)同時管理多個通道的網(wǎng)絡(luò)IO事件,從而提高系統(tǒng)的并發(fā)處理能力。

三. 總結(jié)

Java NIO提供了一套靈活高效的IO操作API,可以幫助我們實現(xiàn)高并發(fā)、高性能的網(wǎng)絡(luò)通信功能。其中包括了Channel、Buffer和Selector三大核心組件,它們共同構(gòu)成了Java NIO的基礎(chǔ)框架。

相比傳統(tǒng)的IO操作方式,Java NIO具有更高的效率、更低的資源占用和更好的可擴(kuò)展性。因此,在開發(fā)高并發(fā)、高性能網(wǎng)絡(luò)應(yīng)用時,我們可以考慮使用Java NIO來實現(xiàn)。

以上就是Java NIO中四大核心組件的使用詳解的詳細(xì)內(nèi)容,更多關(guān)于Java NIO的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • lombok @Accessors用法詳解

    lombok @Accessors用法詳解

    這篇文章主要介紹了lombok @Accessors用法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Java線程的聯(lián)合用法實例分析

    Java線程的聯(lián)合用法實例分析

    這篇文章主要介紹了Java線程的聯(lián)合用法,結(jié)合實例形式分析了java線程聯(lián)合的原理、實現(xiàn)方法及相關(guān)操作技巧,需要的朋友可以參考下
    2019-10-10
  • SpringBoot發(fā)送短信驗證碼的實例

    SpringBoot發(fā)送短信驗證碼的實例

    第三方短信發(fā)送平臺有很多種,各個平臺有各自的優(yōu)缺點,在選擇的時候可以根據(jù)自己的具體實際情況定奪,本文主要介紹了SpringBoot發(fā)送短信驗證碼的實例,感興趣的可以了解一下
    2022-02-02
  • RestTemplate發(fā)送HTTP?GET請求使用方法詳解

    RestTemplate發(fā)送HTTP?GET請求使用方法詳解

    這篇文章主要為大家介紹了關(guān)于RestTemplate發(fā)送HTTP?GET請求的使用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家<BR>33+多多進(jìn)步
    2022-03-03
  • Java多線程CyclicBarrier的實現(xiàn)代碼

    Java多線程CyclicBarrier的實現(xiàn)代碼

    CyclicBarrier可以使一定數(shù)量的線程反復(fù)地在柵欄位置處匯集,本文通過實例代碼介紹下Java多線程CyclicBarrier的相關(guān)知識,感興趣的朋友一起看看吧
    2022-02-02
  • Java emoji持久化mysql過程詳解

    Java emoji持久化mysql過程詳解

    這篇文章主要介紹了Java emoji持久化mysql過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07
  • 一篇文章帶你深入了解Java基礎(chǔ)

    一篇文章帶你深入了解Java基礎(chǔ)

    這篇文章主要給大家介紹了關(guān)于Java中方法使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08
  • 詳解阿里云maven鏡像庫配置(gradle,maven)

    詳解阿里云maven鏡像庫配置(gradle,maven)

    這篇文章主要介紹了詳解阿里云maven鏡像庫配置(gradle,maven),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • springboot指定profiles啟動失敗問題及解決

    springboot指定profiles啟動失敗問題及解決

    這篇文章主要介紹了springboot指定profiles啟動失敗問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • springboot遠(yuǎn)程debug調(diào)試全過程

    springboot遠(yuǎn)程debug調(diào)試全過程

    這篇文章主要介紹了springboot遠(yuǎn)程debug調(diào)試全過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05

最新評論