Many errors related to concurrency happen when memory is shared between different threads, for example, having an object that will be modified by different threads. Sharing memory this way is dangerous because unless there's bulletproof synchronization, there will be scenarios in which the shared object will enter a state that it should never enter—and writing bulletproof synchronization is more difficult than it may seem.
Deadlocks, race conditions, and atomicity violations are related to shared states. Sometimes they happen because a shared state is invalid, and other times they will cause the state to become inconsistent.
In order to overcome these issues, modern programming languages like Kotlin, Go, and Dart provide channels. Channels are tools that will help you write concurrent code, which, instead of sharing a state...