自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Netty學(xué)習(xí)之I/O 模型和Java NIO 編程

開(kāi)發(fā) 前端
同步非阻塞, 服務(wù)器實(shí)現(xiàn)模式為一個(gè)線程處理多個(gè)請(qǐng)求(連接), 即客戶端發(fā)送的連接請(qǐng)求都會(huì)注冊(cè)到多路復(fù)用器上, 多路復(fù)用器輪詢到連接有 I/O 請(qǐng)求就進(jìn)行處理。

一、簡(jiǎn)介

1)Java 共支持 3 種網(wǎng)絡(luò)編程模型/IO 模式: BIO、 NIO、 AIO

2)Java BIO : 同步并阻塞(傳統(tǒng)阻塞型), 服務(wù)器實(shí)現(xiàn)模式為一個(gè)連接一個(gè)線程, 即客戶端有連接請(qǐng)求時(shí)服務(wù)器端就需要啟動(dòng)一個(gè)線程進(jìn)行處理, 如果這個(gè)連接不做任何事情會(huì)造成不必要的線程開(kāi)銷

3)Java NIO : 同步非阻塞, 服務(wù)器實(shí)現(xiàn)模式為一個(gè)線程處理多個(gè)請(qǐng)求(連接), 即客戶端發(fā)送的連接請(qǐng)求都會(huì)注冊(cè)到多路復(fù)用器上, 多路復(fù)用器輪詢到連接有 I/O 請(qǐng)求就進(jìn)行處理。

4)Java AIO(NIO.2) : 異步非阻塞, AIO 引入異步通道的概念, 采用了 Proactor 模式, 簡(jiǎn)化了程序編寫(xiě), 有效的請(qǐng)求才啟動(dòng)線程, 它的特點(diǎn)是先由操作系統(tǒng)完成后才通知服務(wù)端程序啟動(dòng)線程去處理, 一般適用于連接數(shù)較多且連接時(shí)間較長(zhǎng)的應(yīng)用。

二、適用場(chǎng)景

1)BIO 方式適用于連接數(shù)目比較小且固定的架構(gòu), 這種方式對(duì)服務(wù)器資源要求比較高, 并發(fā)局限于應(yīng)用中, JDK1.4以前的唯一選擇, 但程序簡(jiǎn)單易理解。

2)NIO 方式適用于連接數(shù)目多且連接比較短(輕操作) 的架構(gòu), 比如聊天服務(wù)器, 彈幕系統(tǒng), 服務(wù)器間通訊等。編程比較復(fù)雜, JDK1.4 開(kāi)始支持。

  1. AIO 方式使用于連接數(shù)目多且連接比較長(zhǎng)(重操作) 的架構(gòu), 比如相冊(cè)服務(wù)器, 充分調(diào)用 OS 參與并發(fā)操作,編程比較復(fù)雜, JDK7 開(kāi)始支持。

三、Java NIO 編程

3.1 Java NIO 基本介紹

  1. Java NIO 全稱 java non-blocking IO, 是指 JDK 提供的新 API。 從 JDK1.4 開(kāi)始, Java 提供了一系列改進(jìn)的輸入/輸出的新特性, 被統(tǒng)稱為 NIO(即 New IO), 是同步非阻塞的。
  2. NIO 相關(guān)類都被放在 java.nio 包及子包下, 并且對(duì)原 java.io 包中的很多類進(jìn)行改寫(xiě)。
  3. NIO 有三大核心部分: Channel(通道), Buffer(緩沖區(qū)), Selector(選擇器)
  4. NIO 是 面向緩沖區(qū) , 或者面向 塊 編程的。 數(shù)據(jù)讀取到一個(gè)它稍后處理的緩沖區(qū), 需要時(shí)可在緩沖區(qū)中前后移動(dòng), 這就增加了處理過(guò)程中的靈活性, 使用它可以提供非阻塞式的高伸縮性網(wǎng)絡(luò)
  5. Java NIO 的非阻塞模式, 使一個(gè)線程從某通道發(fā)送請(qǐng)求或者讀取數(shù)據(jù), 但是它僅能得到目前可用的數(shù)據(jù), 如果目前沒(méi)有數(shù)據(jù)可用時(shí), 就什么都不會(huì)獲取, 而不是保持線程阻塞, 所以直至數(shù)據(jù)變的可以讀取之前, 該線程可以繼續(xù)做其他的事情。 非阻塞寫(xiě)也是如此, 一個(gè)線程請(qǐng)求寫(xiě)入一些數(shù)據(jù)到某通道, 但不需要等待它完全寫(xiě)入,這個(gè)線程同時(shí)可以去做別的事情。

3.2 NIO 和 BIO 的比較

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

3.3 NIO三大核心原理圖

3.3.1 Selector 、 Channel 和 Buffer 的關(guān)系圖

每個(gè) channel 都會(huì)對(duì)應(yīng)一個(gè) Buffer

  1. Selector 對(duì)應(yīng)一個(gè)線程, 一個(gè)線程對(duì)應(yīng)多個(gè) channel(連接)
  2. 該圖反應(yīng)了有三個(gè) channel 注冊(cè)到 該 selector //程序
  3. 程序切換到哪個(gè) channel 是由事件決定的, Event 就是一個(gè)重要的概念
  4. Selector 會(huì)根據(jù)不同的事件, 在各個(gè)通道上切換
  5. Buffer 就是一個(gè)內(nèi)存塊 , 底層是有一個(gè)數(shù)組
  6. 數(shù)據(jù)的讀取寫(xiě)入是通過(guò) Buffer, 這個(gè)和 BIO , BIO 中要么是輸入流, 或者是

輸出流, 不能雙向, 但是 NIO 的 Buffer 是可以讀也可以寫(xiě), 需要 flip 方法切換

channel 是雙向的, 可以返回底層操作系統(tǒng)的情況, 比如 Linux , 底層的操作系統(tǒng)

通道就是雙向的

3.4 緩沖區(qū)(Buffer)

3.4.1基本介紹

緩沖區(qū)(Buffer) : 緩沖區(qū)本質(zhì)上是一個(gè)可以讀寫(xiě)數(shù)據(jù)的內(nèi)存塊, 可以理解成是一個(gè)容器對(duì)象(含數(shù)組), 該對(duì)象提供了一組方法, 可以更輕松地使用內(nèi)存塊,緩沖區(qū)對(duì)象內(nèi)置了一些機(jī)制, 能夠跟蹤和記錄緩沖區(qū)的狀態(tài)變化情況。 Channel 提供從文件、 網(wǎng)絡(luò)讀取數(shù)據(jù)的渠道, 但是讀取或?qū)懭氲臄?shù)據(jù)都必須經(jīng)由 Buffer, 如圖:

3.4.2 Buffer 類及其子類

  1. Buffer 類定義了所有的緩沖區(qū)都具有的四個(gè)屬性來(lái)提供關(guān)于其所包含的數(shù)據(jù)元素的信息:

2)Buffer 類相關(guān)方法一覽

3.4.3 ByteBuffer

3.5 通道(Channel)

基本介紹

  1. NIO 的通道類似于流, 但有些區(qū)別如下:

? 通道可以同時(shí)進(jìn)行讀寫(xiě), 而流只能讀或者只能寫(xiě)

? 通道可以實(shí)現(xiàn)異步讀寫(xiě)數(shù)據(jù)

? 通道可以從緩沖讀數(shù)據(jù), 也可以寫(xiě)數(shù)據(jù)到緩沖:

  1. 常 用 的 Channel 類 有 : FileChannel 、 DatagramChannel 、ServerSocketChannel 和 SocketChannel 。
  2. FileChannel 用于文件的數(shù)據(jù)讀寫(xiě), DatagramChannel 用于 UDP 的數(shù)據(jù)讀寫(xiě), ServerSocketChannel 和SocketChannel 用于 TCP 的數(shù)據(jù)讀寫(xiě)。

3.6 Selector(選擇器)

3.6.1 基本介紹

  1. Java 的 NIO, 用非阻塞的 IO 方式。 可以用一個(gè)線程, 處理多個(gè)的客戶端連接, 就會(huì)使用到 Selector(選擇器)
  2. Selector 能夠檢測(cè)多個(gè)注冊(cè)的通道上是否有事件發(fā)生(注意:多個(gè) Channel 以事件的方式可以注冊(cè)到同一個(gè)Selector), 如果有事件發(fā)生, 便獲取事件然后針對(duì)每個(gè)事件進(jìn)行相應(yīng)的處理。
  3. 只有在 連接/通道 真正有讀寫(xiě)事件發(fā)生時(shí), 才會(huì)進(jìn)行讀寫(xiě), 就大大地減少了系統(tǒng)開(kāi)銷, 并且不必為每個(gè)連接都創(chuàng)建一個(gè)線程, 不用去維護(hù)多個(gè)線程
  4. 避免了多線程之間的上下文切換導(dǎo)致的開(kāi)銷

3.6.2 Selector 示意圖

  1. Netty 的 IO 線程 NioEventLoop 聚合了 Selector(選擇器, 也叫多路復(fù)用器), 可以同時(shí)并發(fā)處理成百上千個(gè)客戶端連接。
  2. 當(dāng)線程從某客戶端 Socket 通道進(jìn)行讀寫(xiě)數(shù)據(jù)時(shí), 若沒(méi)有數(shù)據(jù)可用時(shí), 該線程可以進(jìn)行其他任務(wù)。
  3. 線程通常將非阻塞 IO 的空閑時(shí)間用于在其他通道上執(zhí)行 IO 操作, 所以單獨(dú)的線程可以管理多個(gè)輸入和輸出通道。
  4. 由于讀寫(xiě)操作都是非阻塞的, 這就可以充分提升 IO 線程的運(yùn)行效率, 避免由于頻繁 I/O 阻塞導(dǎo)致的線程掛起。
  5. 一個(gè) I/O 線程可以并發(fā)處理 N 個(gè)客戶端連接和讀寫(xiě)操作, 這從根本上解決了傳統(tǒng)同步阻塞 I/O 一連接一線程模型, 架構(gòu)的性能、 彈性伸縮能力和可靠性都得到了極大的提升。

3.6.3 Selector方法

public static Selector open():得到一個(gè)選擇器對(duì)象

public int select(long timeout):監(jiān)控所有注冊(cè)的通道,當(dāng)其中IO操作可以進(jìn)行時(shí),將對(duì)應(yīng)的SelectionKey加入到內(nèi)部集合中返回,參數(shù)為超時(shí)時(shí)間

public Set<SlectionKey> selectedKeys():從內(nèi)部集合中得到所有的SlectionKey

selector.select() //阻塞

selector.select(1000) //阻塞1000s

selector.wakeup(); //喚醒 selector

selector.selectNow(); //不阻塞, 立馬返還

3.7 NIO 非阻塞 網(wǎng)絡(luò)編程原理分析圖

NIO 非阻塞 網(wǎng)絡(luò)編程相關(guān)的(Selector、 SelectionKey、 ServerScoketChannel 和 SocketChannel) 關(guān)系梳理圖

  1. 當(dāng)客戶端連接時(shí), 會(huì)通過(guò) ServerSocketChannel 得到 SocketChannel
  2. Selector 進(jìn)行監(jiān)聽(tīng) select 方法, 返回有事件發(fā)生的通道的個(gè)數(shù).
  3. 將 socketChannel 注冊(cè)到 Selector 上, register(Selector sel, int ops), 一個(gè) selector 上可以注冊(cè)多個(gè) SocketChannel
  4. 注冊(cè)后返回一個(gè) SelectionKey, 會(huì)和該 Selector 關(guān)聯(lián)(集合)
  5. 進(jìn)一步得到各個(gè) SelectionKey (有事件發(fā)生)
  6. 在通過(guò) SelectionKey 反向獲取 SocketChannel , 方法 channel()
  7. 可以通過(guò) 得到的 channel , 完成業(yè)務(wù)處理

3.8 SelectionKey

SelectionKey, 表示 Selector 和網(wǎng)絡(luò)通道的注冊(cè)關(guān)系, 共四種:

int OP_ACCEPT: 有新的網(wǎng)絡(luò)連接可以 accept, 值為 16

int OP_CONNECT: 代表連接已經(jīng)建立, 值為 8

int OP_READ: 代表讀操作, 值為 1

int OP_WRITE: 代表寫(xiě)操作, 值為 4

3.9 ServerSocketChannel

ServerSocketChannel 在服務(wù)器端監(jiān)聽(tīng)新的客戶端 Socket 連接

3.10 SocketChannel

SocketChannel,網(wǎng)絡(luò) IO 通道,具體負(fù)責(zé)進(jìn)行讀寫(xiě)操作。NIO 把緩沖區(qū)的數(shù)據(jù)寫(xiě)入通道, 或者把通道里的數(shù)據(jù)讀到緩沖區(qū)。

3.11 NIO 與零拷貝

3.11.1 基本介紹

  1. 在 Java 程序中, 常用的零拷貝有 mmap(內(nèi)存映射) 和 sendFile。
  2. 所謂零拷貝,是從操作系統(tǒng)角度來(lái)看沒(méi)有CPU拷貝。

3.11.2 傳統(tǒng)IO模型

DMA: direct memory access 直接內(nèi)存拷貝(不使用 CPU)

3.11.4 mmap 優(yōu)化

  1. mmap 通過(guò)內(nèi)存映射, 將文件映射到內(nèi)核緩沖區(qū), 同時(shí), 用戶空間可以共享內(nèi)核空間的數(shù)據(jù)。

3.11.5 sendFile 優(yōu)化

  1. Linux 2.1 版本 提供了 sendFile 函數(shù), 其基本原理如下: 數(shù)據(jù)根本不經(jīng)過(guò)用戶態(tài), 直接從內(nèi)核緩沖區(qū)進(jìn)入到Socket Buffer,同時(shí),由于和用戶態(tài)完全無(wú)關(guān),就減少了一次上下文切換。

系統(tǒng)調(diào)用:需要進(jìn)行線程上下文切換,但不是進(jìn)程上下文切換

3.11.6 sendFile改進(jìn)

Linux 在 2.4 版本中, 做了一些修改, 避免了從內(nèi)核緩沖區(qū)拷貝到 Socket buffer 的操作, 直接拷貝到協(xié)議棧,從而再一次減少了數(shù)據(jù)拷貝。

這里還是有一次少量數(shù)據(jù)的CPU拷貝

kernel buffer → socket buffer

拷貝的信息很少,比如length,offset等,消耗很低,可以忽略。

責(zé)任編輯:武曉燕 來(lái)源: 今日頭條
相關(guān)推薦

2021-03-24 08:03:38

NettyJava NIO網(wǎng)絡(luò)技術(shù)

2013-05-28 10:08:41

IO輸出

2020-12-11 11:04:07

NettyIO

2021-02-10 08:09:48

Netty網(wǎng)絡(luò)多路復(fù)用

2023-07-12 08:24:19

Java NIO通道

2021-01-19 06:43:10

Netty框架網(wǎng)絡(luò)技術(shù)

2022-04-16 16:52:24

Netty網(wǎng)絡(luò)服務(wù)器客戶端程序

2020-08-07 08:03:37

IONetty

2013-09-16 16:07:38

Java基礎(chǔ)IO

2023-07-31 08:55:01

Java NIO非阻塞阻塞

2020-06-03 17:30:42

LinuxIO

2010-06-29 09:23:09

JDK 7I|ONIO.2

2023-06-26 07:39:10

2024-11-29 10:23:35

2018-10-08 15:22:36

IO模型

2021-12-27 10:20:46

JavaNetty網(wǎng)絡(luò)

2011-12-15 09:40:06

Javanio

2020-10-10 19:37:27

BIO 、NIO 、A

2010-06-25 09:47:29

Linux系統(tǒng)監(jiān)控

2024-03-05 18:24:52

I/O聚合優(yōu)化存儲(chǔ)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)