关闭Rendezvous Channel为何无法解除已阻塞的send函数?
为什么Rendezvous Channel调用close无法终止阻塞的send?
核心区别:close() 和 cancel() 的作用完全不同
- close() 仅标记通道为关闭状态,拒绝后续新的发送请求,但不会主动中断已经处于阻塞状态的
send()操作。对于容量为0的Rendezvous Channel来说,send()的阻塞逻辑是等待一个接收方来匹配数据传递,close()并不会打破这个等待逻辑——只有当阻塞的send()有机会检测到通道已关闭时(比如后续出现接收操作),才会抛出ClosedSendChannelException并退出阻塞。 - cancel() 是直接取消通道的所有挂起操作,不管是
send()还是receive(),都会被强制中断并抛出CancellationException,直接结束阻塞状态。
结合你的测试代码分析
你的代码中,launch协程里的channel.send(0)因为没有对应的接收方一直处于阻塞状态。调用channel.close()后,通道确实被关闭,但这个阻塞的send()依然在等待接收方,没有触发任何异常的条件——因为close()不会主动唤醒它。所以try块里的代码一直卡在send(),finally块的send over自然无法执行。
如果想要让close()能终止阻塞的send(),需要给send()一个检测通道状态的机会,比如在close后尝试发起一次接收:
@Test fun testCloseRendezvousChannel(): Unit = runBlocking { val channel = Channel<Int>(0) launch { try { println("send begin") channel.send(0) } catch (e: Exception) { println("send caught exception: $e") } finally { println("send over") } } delay(100L) channel.close() // 尝试接收,触发send检测通道关闭状态 runCatching { channel.receive() } println("test over") delay(1000L) }
此时输出会变成:
send begin send caught exception: kotlinx.coroutines.channels.ClosedSendChannelException: Channel was closed send over test over
总结
如果需要立即终止阻塞的send(),直接使用cancel();如果用close(),则需要确保阻塞的send()有机会感知到通道已关闭的状态(比如存在接收操作),否则会一直阻塞下去。
内容的提问来源于stack exchange,提问作者progquester
相关产品推荐
相关产品推荐

