codingstuff.io
ExploreTutorialsProblemsCS Subjects
Get Started
ExploreTutorialsProblemsCS Subjects
Get Started
codingstuff.io

Master the art of building software through interactive tutorials, real-world problems, and guided projects.

Pune, Maharashtra, India

codingstuffmail@gmail.com

Product

  • Explore
  • Tutorials
  • Problems
  • CS Subjects

Company

  • About
  • Contact
  • Privacy Policy
  • Terms & Conditions
  • Sitemap

© 2026 codingstuff.io. All rights reserved.

Built with ❤️ for developers everywhere

/
/
All Tutorials
🎯

Kotlin

25 / 68 topics
23Coroutines Basics24Suspend Functions25Channels in Coroutines26Flow in Kotlin27Concurrency Model28Exception Handling in Coroutines29Async and Await30Structured Concurrency
Tutorials/Kotlin/Channels in Coroutines
🎯Kotlin

Channels in Coroutines

Updated 2026-04-20
3 min read

Introduction

Kotlin's coroutines provide a powerful way to handle asynchronous programming, making it easier to write non-blocking and concurrent code. One of the advanced features of Kotlin coroutines is the use of channels, which allow for safe communication between different coroutines. In this tutorial, we will explore how to use channels in Kotlin coroutines, including their creation, usage, and best practices.

What are Channels?

Channels are a way to send data between coroutines safely and efficiently. They act as conduits through which coroutines can communicate with each other without the need for shared mutable state. This makes them ideal for scenarios where multiple coroutines need to coordinate or exchange data.

Key Concepts

  • Channel: A communication mechanism that allows coroutines to send and receive data.
  • Send Operation: Sending a value to a channel.
  • Receive Operation: Receiving a value from a channel.
  • Buffered Channel: A channel with an internal buffer that can hold multiple values.
  • Rendezvous Channel: A channel without any internal buffer, which means the sender and receiver must coordinate.

Creating Channels

Kotlin provides several ways to create channels, depending on your needs. The most common types are Channel, BufferedChannel, and ConflatedChannel.

Unbuffered Channel (Rendezvous)

An unbuffered channel is a rendezvous channel with no internal buffer. It requires the sender and receiver to be ready at the same time.

import kotlinx.coroutines.*

fun main() = runBlocking {
    val channel = Channel<Int>()

    launch {
        for (x in 1..5) {
            channel.send(x)
            println("Sent $x")
        }
        channel.close()
    }

    for (y in channel) {
        println("Received $y")
    }
}

Buffered Channel

A buffered channel has a fixed-size buffer that can hold multiple values. This allows the sender to send data even if the receiver is not ready.

import kotlinx.coroutines.*

fun main() = runBlocking {
    val channel = Channel<Int>(capacity = 3)

    launch {
        for (x in 1..5) {
            channel.send(x)
            println("Sent $x")
        }
        channel.close()
    }

    for (y in channel) {
        delay(1000) // Simulate some processing time
        println("Received $y")
    }
}

Conflated Channel

A conflated channel holds only the most recent value sent to it. If a new value is sent before the previous one has been received, the old value is discarded.

import kotlinx.coroutines.*

fun main() = runBlocking {
    val channel = Channel<Int>(CONFLATED)

    launch {
        for (x in 1..5) {
            channel.send(x)
            println("Sent $x")
        }
        channel.close()
    }

    for (y in channel) {
        delay(2000) // Simulate some processing time
        println("Received $y")
    }
}

Sending and Receiving Data

Channels provide two main operations: send and receive. The sender coroutine uses the send function to send data, while the receiver coroutine uses the receive function to receive data.

Basic Send and Receive

import kotlinx.coroutines.*

fun main() = runBlocking {
    val channel = Channel<Int>()

    launch {
        for (x in 1..3) {
            channel.send(x)
            println("Sent $x")
        }
        channel.close()
    }

    repeat(3) {
        val y = channel.receive()
        println("Received $y")
    }
}

Using for Loop to Receive

The for loop can be used to receive all values from a channel until it is closed.

import kotlinx.coroutines.*

fun main() = runBlocking {
    val channel = Channel<Int>()

    launch {
        for (x in 1..3) {
            channel.send(x)
            println("Sent $x")
        }
        channel.close()
    }

    for (y in channel) {
        println("Received $y")
    }
}

Handling Exceptions

Channels can throw exceptions if an error occurs during the send or receive operations. It's important to handle these exceptions properly to avoid unexpected behavior.

import kotlinx.coroutines.*

fun main() = runBlocking {
    val channel = Channel<Int>()

    launch {
        try {
            for (x in 1..3) {
                channel.send(x)
                println("Sent $x")
            }
            throw RuntimeException("Simulated error")
        } catch (e: Exception) {
            println("Exception occurred: ${e.message}")
            channel.close(e)
        }
    }

    for (y in channel) {
        println("Received $y")
    }
}

Best Practices

  1. Use Buffered Channels Wisely: While buffered channels can improve performance by allowing the sender to send data without waiting, they also introduce potential issues such as backpressure and memory usage.

  2. Handle Channel Closure Properly: Always check if a channel is closed before attempting to receive data from it. This prevents ChannelClosedException.

  3. Use Conflated Channels for Latest Value: If you only need the most recent value, use a conflated channel to save memory and improve performance.

  4. Avoid Blocking Operations in Coroutines: Channels should not be used to block coroutines indefinitely. Use timeouts or other mechanisms to handle long-running operations.

  5. Test Channel Behavior Thoroughly: Channels can introduce complex behavior due to their asynchronous nature. Ensure that your code is well-tested to handle all possible scenarios.

Conclusion

Channels are a powerful feature of Kotlin coroutines that enable safe and efficient communication between different coroutines. By understanding how to create, use, and manage channels, you can write more robust and scalable concurrent applications. Always consider the specific requirements of your application when choosing the appropriate channel type and handling exceptions properly.


PreviousSuspend FunctionsNext Flow in Kotlin

Recommended Gear

Suspend FunctionsFlow in Kotlin