No Job in newSingleThreadContext and newFixedThreadPoolContext anymore
* This resolves the common issue of using `run(ctx)` where ctx comes from
either `newSingleThreadContext` or `newFixedThreadPoolContext`
invocation. They both used to return a combination of dispatcher + job,
and this job was overriding the parent job, thus preventing propagation
of cancellation. Not anymore.
* ThreadPoolDispatcher class is now public and is the result type for
both functions. It has the `close` method to release the thread pool.
Fixes #149
Fixes #151
diff --git a/coroutines-guide.md b/coroutines-guide.md
index 409602f..6d46817 100644
--- a/coroutines-guide.md
+++ b/coroutines-guide.md
@@ -815,13 +815,17 @@
<!--- TEST LINES_START_UNORDERED -->
-The default dispatcher that we've used in previous sections is representend by [DefaultDispather], which
+The default dispatcher that we've used in previous sections is representend by [DefaultDispatcher], which
is equal to [CommonPool] in the current implementation. So, `launch { ... }` is the same
as `launch(DefaultDispather) { ... }`, which is the same as `launch(CommonPool) { ... }`.
The difference between parent [coroutineContext][CoroutineScope.coroutineContext] and
[Unconfined] context will be shown later.
+Note, that [newSingleThreadContext] creates a new thread, which is a very expensive resource.
+In a real application it must be either released, when no longer needed, using [close][ThreadPoolDispatcher.close]
+function, or stored in a top-level variable and reused throughout the application.
+
### Unconfined vs confined dispatcher
The [Unconfined] coroutine dispatcher starts coroutine in the caller thread, but only until the
@@ -925,22 +929,24 @@
fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
fun main(args: Array<String>) {
- val ctx1 = newSingleThreadContext("Ctx1")
- val ctx2 = newSingleThreadContext("Ctx2")
- runBlocking(ctx1) {
- log("Started in ctx1")
- run(ctx2) {
- log("Working in ctx2")
+ newSingleThreadContext("Ctx1").use { ctx1 ->
+ newSingleThreadContext("Ctx2").use { ctx2 ->
+ runBlocking(ctx1) {
+ log("Started in ctx1")
+ run(ctx2) {
+ log("Working in ctx2")
+ }
+ log("Back to ctx1")
+ }
}
- log("Back to ctx1")
}
}
```
> You can get full code [here](core/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-04.kt)
-It demonstrates two new techniques. One is using [runBlocking] with an explicitly specified context, and
-the second one is using [run] function to change a context of a coroutine while still staying in the
+It demonstrates several new techniques. One is using [runBlocking] with an explicitly specified context, and
+the other one is using [run] function to change a context of a coroutine while still staying in the
same coroutine as you can see in the output below:
```text
@@ -951,6 +957,10 @@
<!--- TEST -->
+
+Note, that is example also uses `use` function from the Kotlin standard library to release threads that
+are created with [newSingleThreadContext] when they are no longer needed.
+
### Job in the context
The coroutine's [Job] is part of its context. The coroutine can retrieve it from its own context
@@ -2325,9 +2335,12 @@
[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/await.html
[Job.start]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/start.html
[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html
+[DefaultDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-default-dispatcher.html
[CommonPool]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-common-pool/index.html
[CoroutineScope.coroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/coroutine-context.html
[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html
+[newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-single-thread-context.html
+[ThreadPoolDispatcher.close]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-thread-pool-dispatcher/close.html
[newCoroutineContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-coroutine-context.html
[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-name/index.html
[Job()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job.html