前言
在之前的文章中,我們已經知道了協程的啟動、掛起、取消、異常以及常用的協程作用域等基礎應用。
這些基礎應用適合的場景是一次性任務,執行完就結束了的場景。
launch / async 適合的場景
- 網絡請求
- 數據庫查詢
- 文件讀寫
- 并行計算任務
- 等等
Channel 適合的場景
而對于一些相對復雜的場景,例如:持續的數據流、需要在不同的協程之間傳遞數據、需要順序或背壓控制等場景,基礎的 launch / async
就不夠用了。
例如:
- 用戶點擊、輸入等事件流的處理
- 生產者-消費者模型的需求:任務排隊、日志流
- 高頻數據源處理(相機幀、音頻流等)
類似這種持續的、需要順序控制、或者多個協程配合執行的場景,就需要用到 Channel
了。
Channel 的概念和基本使用
概念
顧名思義,Channel
有管道、通道的意思。Channel
跟 Java 中的 BlockingQueue
很相似,區別在于 Channel
是掛起的,不是阻塞的。
Channel
的核心特點就是能夠在不同的協程之間進行數據傳遞,并且能夠控制數據傳遞的順序。
使用起來很簡單,基本就分為以下幾步:
- 創建 Channel
- 通過
channel.send
發送數據 - 通過
channel.receive
接收數據
整體的概念也比較簡單形象,就是一根管道,一個口子發送數據,一個口子接收數據。
Channel 的創建
先來看下 Channel 的源碼,可以看到會根據傳入的參數選擇不同的實現。
public fun <E> Channel(capacity: Int = RENDEZVOUS,onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND,onUndeliveredElement: ((E) -> Unit)? = null
): Channel<E> =when (capacity) {RENDEZVOUS -> {if (onBufferOverflow == BufferOverflow.SUSPEND)BufferedChannel(RENDEZVOUS, onUndeliveredElement) // an efficient implementation of rendezvous channelelseConflatedBufferedChannel(1,onBufferOverflow,onUndeliveredElement) // support buffer overflow with buffered channel}CONFLATED -> {require(onBufferOverflow == BufferOverflow.SUSPEND) {"CONFLATED capacity cannot be used with non-default onBufferOverflow"}ConflatedBufferedChannel(1, BufferOverflow.DROP_OLDEST, onUndeliveredElement)}UNLIMITED -> BufferedChannel(UNLIMITED,onUndeliveredElement) // ignores onBufferOverflow: it has buffer, but it never overflowsBUFFERED -> { // uses default capacity with SUSPENDif (onBufferOverflow == BufferOverflow.SUSPEND) BufferedChannel(CHANNEL_DEFAULT_CAPACITY,onUndeliveredElement)else ConflatedBufferedChannel(1, onBufferOverflow, onUndeliveredElement)}else -> {if (onBufferOverflow === BufferOverflow.SUSPEND) BufferedChannel(capacity, onUndeliveredElement)else ConflatedBufferedChannel(capacity, onBufferOverflow, onUndeliveredElement)}}
參數概覽
參數 | 類型 | 默認值 | 描述 |
---|---|---|---|
capacity | Int | RENDEZVOUS | 通道容量,決定緩沖區大小和行為模式 |
onBufferOverflow | BufferOverflow | SUSPEND | 緩沖區溢出時的處理策略 |
onUndeliveredElement | ((E) -> Unit)? | null | 元素未能送達時的回調函數 |
capacity(容量配置)
capacity
參數決定了 Channel
的緩沖行為和容量大小:
RENDEZVOUS
(值為 0):無緩沖,發送者和接收者必須同時準備好CONFLATED
(值為 -1):只保留最新的元素,舊元素會被覆蓋UNLIMITED
(值為Int.MAX_VALUE
):理論上就是無限容量,永不阻塞發送BUFFERED
(值為 64):默認緩沖大小- 自定義正整數:自己指定具體的緩沖區大小
onBufferOverflow(溢出策略)
當緩沖區滿時的處理策略:
SUSPEND
:掛起發送操作,等待緩沖區有空間(默認)DROP_OLDEST
:丟棄舊的元素,添加新元素DROP_LATEST
:丟棄新元素,保留緩沖區中的現有元素
onUndeliveredElement(未送達回調)
當元素無法送達時的清理回調函數:
null
:不執行任何清理操作(默認)- 自定義函數:用于資源清理、日志記錄等,根據業務需求來定義
參數組合效果
capacity | onBufferOverflow | 行為 | 適用場景 |
---|---|---|---|
RENDEZVOUS | SUSPEND | 無緩沖,同步通信 | 嚴格的生產者-消費者同步 |
BUFFERED | SUSPEND | 有限緩沖,滿時掛起 | 一般的異步處理,默認的緩沖數量是 64 |
UNLIMITED | SUSPEND | 緩沖長度為 Int.MAX_VALUE | 高吞吐量場景(生產上不建議使用,有內存方面的風險) |
CONFLATED | DROP_OLDEST | 無緩沖,只保留最新值 | 狀態更新、實時數據 |
自定義大小 | SUSPEND | 固定大小,滿時掛起 | 批量處理、批量任務 |
自定義大小 | DROP_OLDEST | 固定大小,丟棄舊數據 | 獲取最近 N 個元素 |
自定義大小 | DROP_LATEST | 固定大小,拒絕新數據 | 保護重要歷史數據 |
Capacity
RENDEZVOUS(會合模式)
特點:
- 容量為 0,無緩沖區
- 發送者和接收者必須同時準備好才能完成數據傳輸
- 提供強同步保證,一手交錢一手交貨
使用示例:
suspend fun demonstrateRendezvousChannel() {// 創建 RENDEZVOUS Channel(默認容量為 0),默認什么都不傳就是 rendezvous 模式,Channel<String>()val rendezvousChannel = Channel<String>(Channel.RENDEZVOUS)// 啟動發送者協程val senderJob = GlobalScope.launch {println("[發送者] 準備發送消息...")rendezvousChannel.send("Hello from RENDEZVOUS!")println("[發送者] 消息已發送")rendezvousChannel.send("Second message")println("[發送者] 第二條消息已發送")rendezvousChannel.close()}// 啟動接收者協程val receiverJob = GlobalScope.launch {delay(1000) // 延遲1秒,發送者會等待接收者準備好println("[接收者] 開始接收消息...")for (message in rendezvousChannel) {println("[接收者] 收到消息: $message")delay(500) // 模擬處理時間}println("[接收者] Channel已關閉")}// 等待所有協程完成joinAll(senderJob, receiverJob)
}
執行結果
CONFLATED(只留最新值)
特點:
- 容量為 1,但會丟棄舊值
- 只保留最新的元素
- 發送操作永不阻塞
- 只能使用
BufferOverflow.SUSPEND
策略
源碼分析:
CONFLATED -> {require(onBufferOverflow == BufferOverflow.SUSPEND) {"CONFLATED capacity cannot be used with non-default onBufferOverflow"}ConflatedBufferedChannel(1, BufferOverflow.DROP_OLDEST, onUndeliveredElement)
}
使用示例:
suspend fun demonstrateConflatedChannel() {// 創建 CONFLATED Channel,相當于:Channel<String>(1, BufferOverflow.DROP_OLDEST)val conflatedChannel = Channel<String>(Channel.CONFLATED)// 快速發送多個消息val senderJob = GlobalScope.launch {repeat(5) { i ->val message = "Update-$i"conflatedChannel.send(message)println("[發送者] 發送更新: $message")delay(100) // 短暫延遲}conflatedChannel.close()}// 慢速接收者val receiverJob = GlobalScope.launch {delay(1000) // 延遲1秒,讓發送者發送完所有消息println("[接收者] 開始接收(只會收到最新的值)...")for (message in conflatedChannel) {println("[接收者] 收到: $message")}}joinAll(senderJob, receiverJob)
}
UNLIMITED(無限容量)
特點:
- 容量為
Int.MAX_VALUE
,理論上無限容量 - 發送操作永不阻塞,但要注意內存使用
- 忽略
onBufferOverflow
參數 - 適用于高吞吐量場景,但生產環境需謹慎使用
suspend fun demonstrateUnlimitedChannel() {val unlimitedChannel = Channel<String>(Channel.UNLIMITED)val senderJob = GlobalScope.launch {repeat(10) { i ->val message = "Message-$i"unlimitedChannel.send(message)println("[發送者] 立即發送: $message")}unlimitedChannel.close()println("[發送者] 所有消息已發送,Channel已關閉")}val receiverJob = GlobalScope.launch {delay(1000) // 延遲1秒開始接收println("[接收者] 開始慢速接收...")for (message in unlimitedChannel) {println("[接收者] 處理: $message")delay(300) // 模擬處理時間}}joinAll(senderJob, receiverJob)
}
BUFFERED(有限容量)
特點:
- 使用默認容量 (
CHANNEL_DEFAULT_CAPACITY
,通常為 64) - 在緩沖區滿時根據
onBufferOverflow
策略處理
源碼分析:
BUFFERED -> {if (onBufferOverflow == BufferOverflow.SUSPEND)BufferedChannel(CHANNEL_DEFAULT_CAPACITY, onUndeliveredElement)elseConflatedBufferedChannel(1, onBufferOverflow, onUndeliveredElement)
}
使用示例:
suspend fun demonstrateBufferedDefaultChannel() {// 創建 BUFFERED Channel(默認容量為 64)val bufferedChannel = Channel<String>(Channel.BUFFERED)val senderJob = GlobalScope.launch {repeat(100) { i ->bufferedChannel.send("Message-$i")println("[發送者] 發送 Message-$i")}bufferedChannel.close()}val receiverJob = GlobalScope.launch {delay(1000) // 延遲接收for (message in bufferedChannel) {println("[接收者] 收到: $message")delay(50)}}joinAll(senderJob, receiverJob)
}
與下面自定義容量效果類似。
自定義容量
特點:
- 指定具體的緩沖區大小
- 根據
onBufferOverflow
策略處理溢出
源碼分析:
else -> {if (onBufferOverflow === BufferOverflow.SUSPEND)BufferedChannel(capacity, onUndeliveredElement)elseConflatedBufferedChannel(capacity, onBufferOverflow, onUndeliveredElement)
}
使用示例:
suspend fun demonstrateBufferedChannel() {// 創建容量為3的緩沖Channelval bufferedChannel = Channel<Int>(capacity = 3)// 啟動發送者協程val senderJob = GlobalScope.launch {repeat(5) { i ->println("[發送者] 發送數字: $i")bufferedChannel.send(i)println("[發送者] 數字 $i 已發送")}bufferedChannel.close()println("[發送者] Channel已關閉")}// 啟動接收者協程,延遲接收以觀察緩沖效果val receiverJob = GlobalScope.launch {delay(2000) // 延遲2秒開始接收println("[接收者] 開始接收數字...")for (number in bufferedChannel) {println("[接收者] 收到數字: $number")delay(800) // 模擬慢速處理}}joinAll(senderJob, receiverJob)
}
可以看到,因為默認的溢出策略是 SUSPEND
,所以當緩沖區滿了時,發送者會被掛起,直到接收者處理完一個元素,才會繼續發送。
BufferOverflow 策略詳解
當 Channel 的緩沖區滿時,BufferOverflow
參數決定了如何處理新的發送請求:
SUSPEND(默認策略)
- 行為:當緩沖區滿時,掛起發送操作直到有空間可用
- 特點:提供背壓控制,防止生產者過快
- 使用場景:需要確保所有數據都被處理的場景
suspend fun demonstrateBasicOperations() {//容量為 2,溢出策略為SUSPENDval channel = Channel<String>(capacity = 2, onBufferOverflow = BufferOverflow.SUSPEND)//發送的速度快val job1 = GlobalScope.launch {repeat(5) {channel.send("Message-$it")println("[發送者] 發送 Message-$it")}channel.close()}val job2 = GlobalScope.launch {//除了用 channel.recrive 外,也可以直接 用 for 循環接收數據for (message in channel) {//接收的速度慢delay(1000)println("[接收者] 接收到: $message")}}joinAll(job1, job2)
}
DROP_LATEST
- 行為:當緩沖區滿時,丟棄新元素,保留緩沖區中的現有元素
- 特點:保護已緩沖的數據不被覆蓋
- 使用場景:保護重要的歷史數據,防止新數據覆蓋
- 性能特點:發送操作永不阻塞,但新數據可能被丟棄
suspend fun demonstrateBasicOperations() {val channel = Channel<String>(capacity = 2, onBufferOverflow = BufferOverflow.DROP_LATEST)val job1 = GlobalScope.launch {repeat(5) {channel.send("Message-$it")println("[發送者] 發送 Message-$it")}channel.close()}val job2 = GlobalScope.launch {for (message in channel) {delay(1000)println("[接收者] 接收到: $message")}}joinAll(job1, job2)
}
可以看到,當緩沖區滿時,會把新數據丟棄掉,因此,接收端只接收到了舊數據。
DROP_OLDEST
- 行為:當緩沖區滿時,丟棄舊的元素,添加新元素
- 特點:保持固定的內存使用,優先保留新數據
- 使用場景:實時數據流、最近N個元素
- 性能特點:發送操作永不阻塞,但可能丟失歷史數據
suspend fun demonstrateBasicOperations() {val channel = Channel<String>(capacity = 2, onBufferOverflow = BufferOverflow.DROP_OLDEST)val job1 = GlobalScope.launch {repeat(5) {channel.send("Message-$it")println("[發送者] 發送 Message-$it")}channel.close()}val job2 = GlobalScope.launch {for (message in channel) {delay(1000)println("[接收者] 接收到: $message")}}joinAll(job1, job2)
}
需要注意的是,當緩沖區滿了之后,1 和 2 被丟棄了,3 和 4 被放進去了。從這里可以看出,丟棄數據時,并不是把最早的舊數據丟掉,這里跟內部的實現有關。
onUndeliveredElement 回調
當元素無法送達時(如 Channel 被取消或關閉),會調用此回調函數
suspend fun demonstrateBasicOperations() {val channel = Channel<String>(capacity = 2, onBufferOverflow = BufferOverflow.DROP_OLDEST) {println("[Channel] 緩沖區已滿,無法放到緩沖區,值:${it}")}// 演示基本的send和receive操作val job1 = GlobalScope.launch {repeat(5) {channel.send("Message-$it")println("[發送者] 發送 Message-$it")}channel.close()}val job2 = GlobalScope.launch {for (message in channel) {delay(1000)println("[接收者] 接收到: $message")}}joinAll(job1, job2)
}
Channel 操作方式
Channel 提供了兩種操作方式:阻塞操作和非阻塞操作。
阻塞操作(send/receive)
send()
和 receive()
方法都是掛起方法,它們會阻塞當前協程,直到完成操作。
非阻塞操作(trySend/tryReceive)
trySend()
和 tryReceive()
是 Channel 提供的非阻塞操作 API。與阻塞版本不同,這些方法會立即返回結果,不會掛起當前協程,也不會拋出異常。
操作對比
操作類型 | 阻塞版本 | 非阻塞版本 | 行為差異 |
---|---|---|---|
發送 | send() | trySend() | send() 會掛起直到有空間;trySend() 立即返回結果 |
接收 | receive() | tryReceive() | receive() 會掛起直到有數據;tryReceive() 立即返回結果 |
返回值類型
trySend()
返回ChannelResult<Unit>
tryReceive()
返回ChannelResult<T>
ChannelResult
是一個密封類,通過密封類中的成員 isSuccess
和 getOrNull()
可以判斷操作是否成功。
大部分場景下,send / receive + 合理的 Channel 配置就能解決問題,trySend/tryReceive 更多的是想達到如下效果:
- 避免不必要的協程掛起開銷,希望立即得到結果
- 提供更精細的控制邏輯,如:超時處理、重試機制等
- 實現更好的錯誤處理和用戶反饋,能更好地處理異常場景
runBlocking {val channel = Channel<Int>(2)val sendJob = launch {repeat(5) {delay(100)val sendResult = channel.trySend(it)sendResult.onSuccess {println("發送成功")}.onFailure {println("發送失敗")}.onClosed {println("通道已關閉")}}}val receiveJob = launch {for (i in channel) {delay(300)println("接收到數據:${i}")}}joinAll(sendJob, receiveJob)}
Channel 狀態管理
Channel 在其生命周期中會經歷以下幾個關鍵狀態:
- 活躍狀態(Active):可以正常發送和接收數據
- 發送端關閉(Closed for Send):不能發送新數據,但可以接收緩沖區中的數據
- 接收端關閉(Closed for Receive):不能接收數據,緩沖區已清空
- 取消狀態(Cancelled):Channel 被取消,所有操作都會失敗
API
channel.close()
:關閉 Channelchannel.isClosedForSend
:判斷發送端是否已關閉channel.isClosedForReceive
:判斷接收端是否已關閉channel.cancel()
:取消 Channel
Close(關閉操作)
- 調用
close()
后,isClosedForSend
立即變為true
- 此時,緩沖區中的數據仍可被消費
- 只有當緩沖區清空后,
isClosedForReceive
才變為true
示例:
suspend fun demonstrateChannelClose() {val channel = Channel<String>(1)val producer = GlobalScope.launch {try {for (i in 1..5) {val message = "Message $i"println("準備發送: $message")channel.send(message)println("成功發送: $message")delay(100)}} catch (e: ClosedSendChannelException) {println("生產者: Channel已關閉,無法發送數據 - ${e.message}")}}val consumer = GlobalScope.launch {try {for (message in channel) {println("接收到: $message")delay(200)}println("消費者: Channel已關閉,退出接收循環")} catch (e: Exception) {println("消費者異常: ${e.message}")}}delay(300) // 模擬讓一些數據能夠被接收到// 檢查Channel狀態println("關閉前狀態:")println(" isClosedForSend: ${channel.isClosedForSend}")println(" isClosedForReceive: ${channel.isClosedForReceive}")// 關閉Channelprintln("\n正在關閉Channel...")channel.close()// 檢查關閉后的狀態println("關閉后狀態:")println(" isClosedForSend: ${channel.isClosedForSend}")println(" isClosedForReceive: ${channel.isClosedForReceive}")// 等待協程完成producer.join()consumer.join()println("最終狀態:")println(" isClosedForSend: ${channel.isClosedForSend}")println(" isClosedForReceive: ${channel.isClosedForReceive}")
}
Cancel(取消操作)
cancel()
方法用于強制取消 Channel,它會:
- 立即關閉發送和接收端
- 清空緩沖區中的所有數據
- 觸發
onUndeliveredElement
回調(如果設置了)
suspend fun demonstrateChannelCancel() {val channel = Channel<String>(capacity = 5) {println("消息未被接收:${it}")}val producer = GlobalScope.launch {try {for (i in 1..8) {val message = "Message $i"println("嘗試發送: $message")channel.send(message)println("成功發送: $message")delay(100)}} catch (e: CancellationException) {println("生產者: Channel被取消 - ${e.message}")}}val consumer = GlobalScope.launch {try {for (message in channel) {println("接收到: $message")delay(300)}} catch (e: CancellationException) {println("消費者: 協程被取消 - ${e.message}")}}delay(400) // 讓一些操作執行println("\n取消前狀態:")println(" isClosedForSend: ${channel.isClosedForSend}")println(" isClosedForReceive: ${channel.isClosedForReceive}")// 取消Channelprintln("\n正在取消Channel...")channel.cancel(CancellationException("主動取消Channel"))println("取消后狀態:")println(" isClosedForSend: ${channel.isClosedForSend}")println(" isClosedForReceive: ${channel.isClosedForReceive}")// 等待協程完成producer.join()consumer.join()
}
Channel 異常處理
在使用 Channel 的過程中,會遇到各種異常情況。主要包括以下幾種類型:
ClosedSendChannelException
觸發條件:
- 在已關閉的 Channel 上調用
send()
方法 - Channel 調用
close()
后,發送端立即關閉
示例:
suspend fun demonstrateClosedSendException() {val channel = Channel<String>()// 關閉 Channelchannel.close()try {// 嘗試在已關閉的 Channel 上發送數據channel.send("This will throw exception")} catch (e: ClosedSendChannelException) {println("捕獲異常: ${e.message}")println("異常類型: ${e::class.simpleName}")}
}
ClosedReceiveChannelException
觸發條件:
- 從已關閉且緩沖區為空的 Channel 調用
receive()
方法 - 當
isClosedForReceive
為true
時調用receive()
示例:
suspend fun demonstrateClosedReceiveException() {val channel = Channel<String>()// 關閉 Channelchannel.close()try {// 嘗試從已關閉且空的 Channel 接收數據val message = channel.receive()println("收到消息: $message")} catch (e: ClosedReceiveChannelException) {println("捕獲異常: ${e.message}")println("異常類型: ${e::class.simpleName}")}
}
CancellationException
觸發條件:
- Channel 被
cancel()
方法取消 - 父協程被取消,導致 Channel 操作被取消
- 超時或其他取消信號
示例:
suspend fun demonstrateCancellationException() {val channel = Channel<String>()val job = GlobalScope.launch {try {// 這個操作會被取消channel.send("This will be cancelled")} catch (e: CancellationException) {println("發送操作被取消: ${e.message}")throw e // 重新拋出 CancellationException}}delay(100)// 取消 Channelchannel.cancel(CancellationException("手動取消 Channel"))try {job.join()} catch (e: CancellationException) {println("協程被取消: ${e.message}")}
}
異常與狀態關系
Channel 狀態 | send() 行為 | receive() 行為 | trySend() 行為 | tryReceive() 行為 |
---|---|---|---|---|
活躍狀態 | 正常發送或掛起 | 正常接收或掛起 | 返回成功/失敗結果 | 返回成功/失敗結果 |
發送端關閉 | 拋出 ClosedSendChannelException | 正常接收緩沖區數據 | 返回失敗結果 | 正常返回結果 |
接收端關閉 | 拋出 ClosedSendChannelException | 拋出 ClosedReceiveChannelException | 返回失敗結果 | 返回失敗結果 |
已取消 | 拋出 CancellationException | 拋出 CancellationException | 返回失敗結果 | 返回失敗結果 |
異常處理技巧
使用非阻塞操作避免異常
非阻塞操作不會拋出異常,而是返回結果對象:
suspend fun safeChannelOperations() {val channel = Channel<String>()// 安全的發送操作val sendResult = channel.trySend("Safe message")when {sendResult.isSuccess -> println("發送成功")sendResult.isFailure -> println("發送失敗: ${sendResult.exceptionOrNull()}")sendResult.isClosed -> println("Channel 已關閉")}// 安全的接收操作val receiveResult = channel.tryReceive()when {receiveResult.isSuccess -> println("接收到: ${receiveResult.getOrNull()}")receiveResult.isFailure -> println("接收失敗: ${receiveResult.exceptionOrNull()}")receiveResult.isClosed -> println("Channel 已關閉")}
}
健壯的異常處理
suspend fun robustChannelUsage() {val channel = Channel<String>()val producer = GlobalScope.launch {try {repeat(5) { i ->if (channel.isClosedForSend) {println("Channel 已關閉,停止發送")break}channel.send("Message $i")delay(100)}} catch (e: ClosedSendChannelException) {println("生產者: Channel 已關閉")} catch (e: CancellationException) {println("生產者: 操作被取消")throw e // 重新拋出取消異常} finally {println("生產者: 清理資源")}}val consumer = GlobalScope.launch {try {while (!channel.isClosedForReceive) {try {val message = channel.receive()println("消費者: 收到 $message")} catch (e: ClosedReceiveChannelException) {println("消費者: Channel 已關閉且無更多數據")break}delay(200)}} catch (e: CancellationException) {println("消費者: 操作被取消")throw e} finally {println("消費者: 清理資源")}}delay(1000)channel.close()joinAll(producer, consumer)
}
總結
Channel 關鍵概念對比
特性 | RENDEZVOUS | CONFLATED | BUFFERED | UNLIMITED | 自定義容量 |
---|---|---|---|---|---|
容量 | 0 | 1 | 64 | Int.MAX_VALUE | 指定值 |
緩沖行為 | 無緩沖,同步 | 只保留最新值 | 有限緩沖 | 無限緩沖 | 有限緩沖 |
發送阻塞 | 是 | 否 | 緩沖滿時 | 否 | 緩沖滿時 |
適用場景 | 嚴格同步 | 狀態更新 | 一般異步 | 高吞吐量 | 批量處理 |
內存風險 | 低 | 低 | 中等 | 高 | 可控 |
溢出策略對比
策略 | 行為 | 性能特點 | 適用場景 |
---|---|---|---|
SUSPEND | 掛起發送操作 | 提供背壓控制 | 確保數據完整性 |
DROP_OLDEST | 丟棄舊元素 | 發送不阻塞 | 實時數據流 |
DROP_LATEST | 丟棄新元素 | 發送不阻塞 | 保護歷史數據 |
操作方式
操作類型 | 阻塞版本 | 非阻塞版本 | 異常處理 | 返回值 |
---|---|---|---|---|
發送 | send() | trySend() | 拋出異常 | ChannelResult<Unit> |
接收 | receive() | tryReceive() | 拋出異常 | ChannelResult<T> |
特點 | 會掛起協程 | 立即返回 | 需要 try-catch | 通過結果對象判斷 |
Channel 狀態生命周期
狀態 | 描述 | send() | receive() | 檢查方法 |
---|---|---|---|---|
活躍 | 正常工作狀態 | ? 正常 | ? 正常 | - |
發送關閉 | 調用 close() 后 | ? 異常 | ? 可接收緩沖區數據 | isClosedForSend |
接收關閉 | 緩沖區清空后 | ? 異常 | ? 異常 | isClosedForReceive |
已取消 | 調用 cancel() 后 | ? 異常 | ? 異常 | - |
總體來說,Channel 是一種非常強大的協程通信機制,它可以幫助我們在協程之間進行安全、高效的通信。在使用 Channel時,我們需要注意異常處理、緩沖區容量、溢出策略等問題。
感謝閱讀,如果對你有幫助請三連(點贊、收藏、加關注)支持。有任何疑問或建議,歡迎在評論區留言討論。如需轉載,請注明出處:喻志強的博客