Understanding Kotlin/Native Asynchronous Concurrency: Workers, Object Subgraphs, and Multithreaded Coroutines
This article explores Kotlin/Native's asynchronous concurrency model, detailing the three native approaches—OS‑level threads, Kotlin/Native coroutines, and Workers with object subgraphs—while also examining the preview multithreaded coroutine support, transfer modes, annotations, and practical code examples.
Kotlin/Native, a key component of Kotlin Multiplatform, is still in beta and implements its own asynchronous concurrency model that differs significantly from Kotlin/JVM's coroutine‑based approach. While Kotlin/JVM relies on compiler‑generated coroutines and thread pools, Kotlin/Native must provide native mechanisms because it produces standalone binaries without a JVM.
The native concurrency options are threefold:
Directly using the host operating system's APIs (e.g., POSIX pthread_create ) to spawn threads, which sacrifices portability.
Kotlin/Native's own coroutine API, which is single‑threaded and suitable only for non‑CPU‑intensive tasks such as network I/O. A preview multithreaded coroutine version was released in December 2019.
The Worker API, tightly coupled with the object‑subgraph model, enabling true multithreaded execution while guaranteeing thread safety through object freezing.
Workers behave like threads; each Worker corresponds to a thread on POSIX systems. Objects accessed across Workers must be either frozen (immutable) or explicitly marked with @SharedImmutable . Frozen objects can be read from any Worker, while mutable objects require careful handling to avoid IncorrectDereferenceException .
Example of creating a Worker and executing a task:
fun main() { val worker = Worker.start(true, "worker1") println("Position 1, thread id: ${pthread_self()!!.rawValue.toLong()}") val future = worker.execute(TransferMode.SAFE, { println("Position 2, thread id: ${pthread_self()!!.rawValue.toLong()}") 1 + 2 }) { println("Position 3, thread id: ${pthread_self()!!.rawValue.toLong()}") (it + 100).toString() } future.consume { println("Position 4, thread id: ${pthread_self()!!.rawValue.toLong()}") println("Result: $it") } }The output shows that the producer and the consume callback run on the main thread, while the job runs on a background thread.
When passing mutable objects to a Worker, the TransferMode.UNSAFE mode allows it but leads to data races, as demonstrated by a benchmark that should produce 40 000 increments but yields a smaller, nondeterministic result.
Annotations control object mutability across Workers:
@ThreadLocal creates a separate copy per thread, making changes invisible to other threads.
@SharedImmutable marks an object as immutable and safely shareable.
Singleton objects declared with object are frozen by default but can be made thread‑local with @ThreadLocal .
The preview multithreaded coroutine support introduces several breaking changes:
Dispatchers.Default now points to a background thread instead of the main thread.
Mutex implementations currently contain a bug that can deadlock coroutines.
Memory leaks and limited dispatcher functionality are known issues.
Example of adding the preview coroutine dependency:
dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.3.3-native-mt" }Using newSingleThreadContext creates dedicated threads for CPU‑bound work, but developers must manage the lifecycle of the created CoroutineContext and close it when done.
Object subgraph separation can be achieved with DetachedObjectGraph in UNSAFE mode, allowing mutable objects to be transferred to coroutines. However, the current preview version’s Mutex bug makes this approach unreliable.
In summary, Kotlin/Native offers two mature concurrency models—Workers with object subgraphs and the emerging multithreaded coroutines. Workers provide safety through freezing, while the coroutine preview promises more idiomatic Kotlin code but still suffers from stability issues. Developers should prefer the safe SAFE transfer mode and use Workers for production code, reserving the multithreaded coroutine preview for experimentation.
Ctrip Technology
Official Ctrip Technology account, sharing and discussing growth.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.