blob: a0e1ffa2c79303f2b0c5c2606da9c7dc8ac3e741 [file] [log] [blame]
/*
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines
import kotlinx.coroutines.internal.*
import java.util.concurrent.*
import java.util.concurrent.atomic.AtomicInteger
import kotlin.coroutines.*
/**
* Creates a coroutine execution context using a single thread with built-in [yield] support.
* **NOTE: The resulting [ExecutorCoroutineDispatcher] owns native resources (its thread).
* Resources are reclaimed by [ExecutorCoroutineDispatcher.close].**
*
* **NOTE: This API will be replaced in the future**. A different API to create thread-limited thread pools
* that is based on a shared thread-pool and does not require the resulting dispatcher to be explicitly closed
* will be provided, thus avoiding potential thread leaks and also significantly improving performance, due
* to coroutine-oriented scheduling policy and thread-switch minimization.
* See [issue #261](https://github.com/Kotlin/kotlinx.coroutines/issues/261) for details.
* If you need a completely separate thread-pool with scheduling policy that is based on the standard
* JDK executors, use the following expression:
* `Executors.newSingleThreadExecutor().asCoroutineDispatcher()`.
* See [Executor.asCoroutineDispatcher] for details.
*
* @param name the base name of the created thread.
*/
@ObsoleteCoroutinesApi
public fun newSingleThreadContext(name: String): ExecutorCoroutineDispatcher =
newFixedThreadPoolContext(1, name)
/**
* Creates a coroutine execution context with the fixed-size thread-pool and built-in [yield] support.
* **NOTE: The resulting [ExecutorCoroutineDispatcher] owns native resources (its threads).
* Resources are reclaimed by [ExecutorCoroutineDispatcher.close].**
*
* **NOTE: This API will be replaced in the future**. A different API to create thread-limited thread pools
* that is based on a shared thread-pool and does not require the resulting dispatcher to be explicitly closed
* will be provided, thus avoiding potential thread leaks and also significantly improving performance, due
* to coroutine-oriented scheduling policy and thread-switch minimization.
* See [issue #261](https://github.com/Kotlin/kotlinx.coroutines/issues/261) for details.
* If you need a completely separate thread-pool with scheduling policy that is based on the standard
* JDK executors, use the following expression:
* `Executors.newFixedThreadPool().asCoroutineDispatcher()`.
* See [Executor.asCoroutineDispatcher] for details.
*
* @param nThreads the number of threads.
* @param name the base name of the created threads.
*/
@ObsoleteCoroutinesApi
public fun newFixedThreadPoolContext(nThreads: Int, name: String): ExecutorCoroutineDispatcher {
require(nThreads >= 1) { "Expected at least one thread, but $nThreads specified" }
return ThreadPoolDispatcher(nThreads, name)
}
internal class PoolThread(
@JvmField val dispatcher: ThreadPoolDispatcher, // for debugging & tests
target: Runnable, name: String
) : Thread(target, name) {
init { isDaemon = true }
}
/**
* Dispatches coroutine execution to a thread pool of a fixed size. Instances of this dispatcher are
* created with [newSingleThreadContext] and [newFixedThreadPoolContext].
*/
internal class ThreadPoolDispatcher internal constructor(
private val nThreads: Int,
private val name: String
) : ExecutorCoroutineDispatcherBase() {
private val threadNo = AtomicInteger()
override val executor: Executor = Executors.newScheduledThreadPool(nThreads) { target ->
PoolThread(this, target, if (nThreads == 1) name else name + "-" + threadNo.incrementAndGet())
}
init {
initFutureCancellation()
}
/**
* Closes this dispatcher -- shuts down all threads in this pool and releases resources.
*/
public override fun close() {
(executor as ExecutorService).shutdown()
}
override fun toString(): String = "ThreadPoolDispatcher[$nThreads, $name]"
}