Channels Flashcards
KOTLIN › Concurrency
- What happens when you call send() on a full channel?
- send() suspends the calling coroutine until there is room in the channel's buffer. It does not block the thread. For an unbuffered (rendezvous) channel, send() suspends until another coroutine calls receive().
- What are the four channel capacity modes and how does each handle a full buffer?
- RENDEZVOUS (capacity 0): send suspends until a receiver is ready. BUFFERED (default 64): send suspends when the buffer is full. CONFLATED: the buffer holds one element and overwrites it on each send, never suspending. UNLIMITED: the buffer grows without bound, send never suspends (risk of OOM).
- What does produce {} return and what happens when its block finishes?
- produce {} is a coroutine builder that returns a ReceiveChannel<T>. When the block completes (normally or by exception), the channel is automatically closed. It is the channel equivalent of a flow builder.
- What is the difference between send() and trySend() on a channel?
- send() is a suspend function that waits until the channel has capacity. trySend() is a non-suspending function that returns a ChannelResult immediately: success if the element was added, failure if the channel is full or closed. Use trySend() from non-suspending code like callbacks.
- How does fan-out work with channels?
- Multiple coroutines call receive() on the same channel. Each element is delivered to exactly one receiver (no duplication). The channel acts as a work queue, distributing items across consumers for parallel processing.
- How does fan-in work with channels?
- Multiple coroutines call send() on the same channel. All elements arrive in a single stream that one (or more) consumers can receive from. The channel merges multiple producers into one output.
- Why are channels called 'hot' while flows are 'cold'?
- A channel is hot because it exists and can buffer elements whether or not anyone is receiving. A flow is cold because it does nothing until collect() is called -- each collector triggers a fresh execution of the flow builder. Channels push eagerly; flows pull lazily.
- What is channelFlow {} and when would you use it over a regular flow {}?
- channelFlow {} creates a cold Flow backed by an internal channel. Unlike flow {}, the block runs in its own coroutine and can launch child coroutines that all call send(). Use it when you need concurrent emission from multiple coroutines inside a flow.
- What happens when you close a channel and a coroutine tries to receive() from it?
- After close(), any elements already in the buffer can still be received. Once the buffer is drained, receive() throws ClosedReceiveChannelException. The safer alternative is receiveCatching(), which returns a ChannelResult instead of throwing.