Kotlin 的 Channel 是协程间通信的核心组件,本质上是一个并发安全的队列,支持生产-消费模式的数据传输。以下是其核心特性的结构化解析:
一、基础概念
- 管道模型
Channel表现为发送方(send)与接收方(receive)之间的通信管道,数据按顺序传递且每个元素仅被一个接收者消费36。默认实现为无缓冲通道(RENDEZVOUS),需发送和接收协程同时就绪才能完成传输4。 - 非阻塞挂起特性
与BlockingQueue不同,send和receive是挂起函数:当缓冲区满或空时自动挂起协程,而非阻塞线程67。
二、基本使用
// 创建 Channel
val channel = Channel<Int>()
// 生产者协程
launch {
repeat(10) {
delay(100)
channel.send(it) // 发送数据
}
channel.close() // 关闭通道
}
// 消费者协程
launch {
for (element in channel) { // 通过迭代接收
println("Received: $element")
}
}
三、类型与容量配置
-
缓冲策略
通过Channel(capacity)构造函数指定缓冲区容量及溢出策略:- RENDEZVOUS(默认):无缓冲,需发送/接收同时就绪4。
- UNLIMITED:无界缓冲区,
send永不挂起7。 - CONFLATED:仅保留最新元素,自动丢弃旧值4。
- BUFFERED:固定大小缓冲区(默认 64)7。
-
溢出处理
通过onBufferOverflow参数定义缓冲区满时的行为:SUSPEND(默认):挂起发送方4。DROP_OLDEST:丢弃最旧元素4。DROP_LATEST:丢弃最新元素4。
四、高级特性
-
关闭与异常处理
- 调用
close()关闭通道,触发接收端的迭代终止4。 - 通过
onUndeliveredElement回调处理未投递元素的清理逻辑(如资源释放)4。
- 调用
-
多接收者竞争
单个元素仅能被一个接收者消费,多个接收者会形成竞争关系4。示例中两个接收者可能交替获取不同元素。
五、与 Flow 的对比
| 特性 | Channel | Flow |
|---|---|---|
| 通信模式 | 点对点(单播) | 广播(冷流) |
| 生命周期 | 主动管理(需手动关闭) | 自动取消 |
| 适用场景 | 协程间实时通信 | 数据流处理(如网络响应) |
六、典型应用场景
- 生产者-消费者模式:如后台任务与 UI 更新的解耦。
- 事件总线:通过
BroadcastChannel(已废弃,推荐SharedFlow)实现多订阅6。 - 多路复用:结合
select实现多个Channel的优先级处理8。
七、案例
fun main():Unit = runBlocking {
val channel = Channel<Int>()
launch {
(1..1000) .forEach{
delay(2000)
channel.send(it)
println("生产一个:$it")
}
}
launch {
(1..1000) .forEach{
delay(2000)
var it = channel.receive()
println("消费一个:$it")
}
}
//channel 是一个队列,默认缓冲区是0
//如果缓冲区满了,如果recevice 没有消费,此时send会挂起,直到receive消费掉,send 再次恢复再生产一个
}
八、注意事项
- 资源泄漏:未关闭的
Channel可能导致协程无法结束4。 - 性能调优:合理选择缓冲区大小与溢出策略,避免频繁挂起或数据丢失