1 /* <lambda>null2 * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.coroutines 6 7 import kotlinx.coroutines.internal.* 8 import java.util.concurrent.* 9 import java.util.concurrent.atomic.AtomicInteger 10 import kotlin.coroutines.* 11 12 /** 13 * Creates a coroutine execution context using a single thread with built-in [yield] support. 14 * **NOTE: The resulting [ExecutorCoroutineDispatcher] owns native resources (its thread). 15 * Resources are reclaimed by [ExecutorCoroutineDispatcher.close].** 16 * 17 * If the resulting dispatcher is [closed][ExecutorCoroutineDispatcher.close] and 18 * attempt to submit a continuation task is made, 19 * then the [Job] of the affected task is [cancelled][Job.cancel] and the task is submitted to the 20 * [Dispatchers.IO], so that the affected coroutine can cleanup its resources and promptly complete. 21 * 22 * **NOTE: This API will be replaced in the future**. A different API to create thread-limited thread pools 23 * that is based on a shared thread-pool and does not require the resulting dispatcher to be explicitly closed 24 * will be provided, thus avoiding potential thread leaks and also significantly improving performance, due 25 * to coroutine-oriented scheduling policy and thread-switch minimization. 26 * See [issue #261](https://github.com/Kotlin/kotlinx.coroutines/issues/261) for details. 27 * If you need a completely separate thread-pool with scheduling policy that is based on the standard 28 * JDK executors, use the following expression: 29 * `Executors.newSingleThreadExecutor().asCoroutineDispatcher()`. 30 * See [Executor.asCoroutineDispatcher] for details. 31 * 32 * @param name the base name of the created thread. 33 */ 34 @ObsoleteCoroutinesApi 35 public fun newSingleThreadContext(name: String): ExecutorCoroutineDispatcher = 36 newFixedThreadPoolContext(1, name) 37 38 /** 39 * Creates a coroutine execution context with the fixed-size thread-pool and built-in [yield] support. 40 * **NOTE: The resulting [ExecutorCoroutineDispatcher] owns native resources (its threads). 41 * Resources are reclaimed by [ExecutorCoroutineDispatcher.close].** 42 * 43 * If the resulting dispatcher is [closed][ExecutorCoroutineDispatcher.close] and 44 * attempt to submit a continuation task is made, 45 * then the [Job] of the affected task is [cancelled][Job.cancel] and the task is submitted to the 46 * [Dispatchers.IO], so that the affected coroutine can cleanup its resources and promptly complete. 47 * 48 * **NOTE: This API will be replaced in the future**. A different API to create thread-limited thread pools 49 * that is based on a shared thread-pool and does not require the resulting dispatcher to be explicitly closed 50 * will be provided, thus avoiding potential thread leaks and also significantly improving performance, due 51 * to coroutine-oriented scheduling policy and thread-switch minimization. 52 * See [issue #261](https://github.com/Kotlin/kotlinx.coroutines/issues/261) for details. 53 * If you need a completely separate thread-pool with scheduling policy that is based on the standard 54 * JDK executors, use the following expression: 55 * `Executors.newFixedThreadPool().asCoroutineDispatcher()`. 56 * See [Executor.asCoroutineDispatcher] for details. 57 * 58 * @param nThreads the number of threads. 59 * @param name the base name of the created threads. 60 */ 61 @ObsoleteCoroutinesApi 62 public fun newFixedThreadPoolContext(nThreads: Int, name: String): ExecutorCoroutineDispatcher { 63 require(nThreads >= 1) { "Expected at least one thread, but $nThreads specified" } 64 return ThreadPoolDispatcher(nThreads, name) 65 } 66 67 internal class PoolThread( 68 @JvmField val dispatcher: ThreadPoolDispatcher, // for debugging & tests 69 target: Runnable, name: String 70 ) : Thread(target, name) { 71 init { isDaemon = true } 72 } 73 74 /** 75 * Dispatches coroutine execution to a thread pool of a fixed size. Instances of this dispatcher are 76 * created with [newSingleThreadContext] and [newFixedThreadPoolContext]. 77 */ 78 internal class ThreadPoolDispatcher internal constructor( 79 private val nThreads: Int, 80 private val name: String 81 ) : ExecutorCoroutineDispatcherBase() { 82 private val threadNo = AtomicInteger() 83 targetnull84 override val executor: Executor = Executors.newScheduledThreadPool(nThreads) { target -> 85 PoolThread(this, target, if (nThreads == 1) name else name + "-" + threadNo.incrementAndGet()) 86 } 87 88 init { 89 initFutureCancellation() 90 } 91 92 /** 93 * Closes this dispatcher -- shuts down all threads in this pool and releases resources. 94 */ closenull95 public override fun close() { 96 (executor as ExecutorService).shutdown() 97 } 98 toStringnull99 override fun toString(): String = "ThreadPoolDispatcher[$nThreads, $name]" 100 } 101