Roman Elizarov | f16fd27 | 2017-02-07 11:26:00 +0300 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2016-2017 JetBrains s.r.o. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 17 | package kotlinx.coroutines.experimental |
| 18 | |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 19 | import java.io.Closeable |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 20 | import java.util.concurrent.Executors |
| 21 | import java.util.concurrent.ScheduledExecutorService |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 22 | import java.util.concurrent.atomic.AtomicInteger |
Roman Elizarov | ea4a51b | 2017-01-31 12:01:25 +0300 | [diff] [blame] | 23 | import kotlin.coroutines.experimental.CoroutineContext |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 24 | |
| 25 | /** |
paolop | 517a259 | 2018-06-09 17:01:53 +0000 | [diff] [blame] | 26 | * Creates a new coroutine execution context using a single thread with built-in [yield] and [delay] support. |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 27 | * **NOTE: The resulting [ThreadPoolDispatcher] owns native resources (its thread). |
| 28 | * Resources are reclaimed by [ThreadPoolDispatcher.close].** |
| 29 | * |
| 30 | * @param name the base name of the created thread. |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 31 | */ |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 32 | fun newSingleThreadContext(name: String): ThreadPoolDispatcher = |
| 33 | newFixedThreadPoolContext(1, name) |
| 34 | |
| 35 | /** |
| 36 | * @suppress **Deprecated**: Parent job is no longer supported. |
| 37 | */ |
| 38 | @Deprecated(message = "Parent job is no longer supported, `close` the resulting ThreadPoolDispatcher to release resources", |
| 39 | level = DeprecationLevel.WARNING, replaceWith = ReplaceWith("newSingleThreadContext(name)")) |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 40 | fun newSingleThreadContext(name: String, parent: Job? = null): CoroutineContext = |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 41 | newFixedThreadPoolContext(1, name) |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 42 | |
| 43 | /** |
Roman Elizarov | 67891d8 | 2017-01-23 16:47:20 +0300 | [diff] [blame] | 44 | * Creates new coroutine execution context with the fixed-size thread-pool and built-in [yield] and [delay] support. |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 45 | * **NOTE: The resulting [ThreadPoolDispatcher] owns native resources (its threads). |
| 46 | * Resources are reclaimed by [ThreadPoolDispatcher.close].** |
| 47 | * |
| 48 | * @param nThreads the number of threads. |
| 49 | * @param name the base name of the created threads. |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 50 | */ |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 51 | fun newFixedThreadPoolContext(nThreads: Int, name: String): ThreadPoolDispatcher { |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 52 | require(nThreads >= 1) { "Expected at least one thread, but $nThreads specified" } |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 53 | return ThreadPoolDispatcher(nThreads, name) |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 54 | } |
| 55 | |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 56 | /** |
| 57 | * @suppress **Deprecated**: Parent job is no longer supported. |
| 58 | */ |
| 59 | @Deprecated(message = "Parent job is no longer supported, `close` the resulting ThreadPoolDispatcher to release resources", |
| 60 | level = DeprecationLevel.WARNING, replaceWith = ReplaceWith("newFixedThreadPoolContext(nThreads, name)")) |
| 61 | fun newFixedThreadPoolContext(nThreads: Int, name: String, parent: Job? = null): CoroutineContext = |
| 62 | newFixedThreadPoolContext(nThreads, name) |
| 63 | |
Roman Elizarov | 731f0ad | 2017-02-22 20:48:45 +0300 | [diff] [blame] | 64 | internal class PoolThread( |
Roman Elizarov | f04f51d | 2017-04-18 15:28:35 +0300 | [diff] [blame] | 65 | @JvmField val dispatcher: ThreadPoolDispatcher, // for debugging & tests |
Roman Elizarov | 731f0ad | 2017-02-22 20:48:45 +0300 | [diff] [blame] | 66 | target: Runnable, name: String |
| 67 | ) : Thread(target, name) { |
| 68 | init { isDaemon = true } |
| 69 | } |
| 70 | |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 71 | /** |
| 72 | * Dispatches coroutine execution to a thread pool of a fixed size. Instances of this dispatcher are |
| 73 | * created with [newSingleThreadContext] and [newFixedThreadPoolContext]. |
| 74 | */ |
| 75 | public class ThreadPoolDispatcher internal constructor( |
Roman Elizarov | f04f51d | 2017-04-18 15:28:35 +0300 | [diff] [blame] | 76 | private val nThreads: Int, |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 77 | private val name: String |
| 78 | ) : ExecutorCoroutineDispatcherBase(), Closeable { |
Roman Elizarov | f04f51d | 2017-04-18 15:28:35 +0300 | [diff] [blame] | 79 | private val threadNo = AtomicInteger() |
| 80 | |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 81 | internal override val executor: ScheduledExecutorService = Executors.newScheduledThreadPool(nThreads) { target -> |
Roman Elizarov | 731f0ad | 2017-02-22 20:48:45 +0300 | [diff] [blame] | 82 | PoolThread(this, target, if (nThreads == 1) name else name + "-" + threadNo.incrementAndGet()) |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 83 | } |
| 84 | |
Roman Elizarov | d9ae2bc | 2017-10-20 17:36:56 +0800 | [diff] [blame] | 85 | /** |
| 86 | * Closes this dispatcher -- shuts down all threads in this pool and releases resources. |
| 87 | */ |
| 88 | public override fun close() { |
| 89 | executor.shutdown() |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 90 | } |
| 91 | |
Roman Elizarov | f04f51d | 2017-04-18 15:28:35 +0300 | [diff] [blame] | 92 | override fun toString(): String = "ThreadPoolDispatcher[$nThreads, $name]" |
Roman Elizarov | 3754f95 | 2017-01-18 20:47:54 +0300 | [diff] [blame] | 93 | } |