This question came up after reading the Loom proposal, which describes an approach of implementing coroutines in the Java programming language.
Particularly this pro
From the Kotlin Documentation on Coroutines (emphasis mine):
Coroutines simplify asynchronous programming by putting the complications into libraries. The logic of the program can be expressed sequentially in a coroutine, and the underlying library will figure out the asynchrony for us. The library can wrap relevant parts of the user code into callbacks, subscribe to relevant events, schedule execution on different threads (or even different machines!), and the code remains as simple as if it was sequentially executed.
Long story short, they are compiled down to code that uses callbacks and a state machine to handle suspending and resuming.
Roman Elizarov, the project lead, gave two fantastic talks at KotlinConf 2017 on this subject. One is an Introduction to Coroutines, the second is a Deep Dive on Coroutines.