blob: e8777282bc63014c5119713bb98de7f54e524d7f [file] [log] [blame]
Roman Elizarovf16fd272017-02-07 11:26:00 +03001/*
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 Elizarov3754f952017-01-18 20:47:54 +030017package kotlinx.coroutines.experimental
18
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080019import java.io.Closeable
Roman Elizarov3754f952017-01-18 20:47:54 +030020import java.util.concurrent.Executors
21import java.util.concurrent.ScheduledExecutorService
Roman Elizarov3754f952017-01-18 20:47:54 +030022import java.util.concurrent.atomic.AtomicInteger
Roman Elizarovea4a51b2017-01-31 12:01:25 +030023import kotlin.coroutines.experimental.CoroutineContext
Roman Elizarov3754f952017-01-18 20:47:54 +030024
25/**
paolop517a2592018-06-09 17:01:53 +000026 * Creates a new coroutine execution context using a single thread with built-in [yield] and [delay] support.
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080027 * **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 Elizarov3754f952017-01-18 20:47:54 +030031 */
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080032fun 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 Elizarov3754f952017-01-18 20:47:54 +030040fun newSingleThreadContext(name: String, parent: Job? = null): CoroutineContext =
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080041 newFixedThreadPoolContext(1, name)
Roman Elizarov3754f952017-01-18 20:47:54 +030042
43/**
Roman Elizarov67891d82017-01-23 16:47:20 +030044 * Creates new coroutine execution context with the fixed-size thread-pool and built-in [yield] and [delay] support.
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080045 * **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 Elizarov3754f952017-01-18 20:47:54 +030050 */
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080051fun newFixedThreadPoolContext(nThreads: Int, name: String): ThreadPoolDispatcher {
Roman Elizarov3754f952017-01-18 20:47:54 +030052 require(nThreads >= 1) { "Expected at least one thread, but $nThreads specified" }
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080053 return ThreadPoolDispatcher(nThreads, name)
Roman Elizarov3754f952017-01-18 20:47:54 +030054}
55
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080056/**
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)"))
61fun newFixedThreadPoolContext(nThreads: Int, name: String, parent: Job? = null): CoroutineContext =
62 newFixedThreadPoolContext(nThreads, name)
63
Roman Elizarov731f0ad2017-02-22 20:48:45 +030064internal class PoolThread(
Roman Elizarovf04f51d2017-04-18 15:28:35 +030065 @JvmField val dispatcher: ThreadPoolDispatcher, // for debugging & tests
Roman Elizarov731f0ad2017-02-22 20:48:45 +030066 target: Runnable, name: String
67) : Thread(target, name) {
68 init { isDaemon = true }
69}
70
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080071/**
72 * Dispatches coroutine execution to a thread pool of a fixed size. Instances of this dispatcher are
73 * created with [newSingleThreadContext] and [newFixedThreadPoolContext].
74 */
75public class ThreadPoolDispatcher internal constructor(
Roman Elizarovf04f51d2017-04-18 15:28:35 +030076 private val nThreads: Int,
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080077 private val name: String
78) : ExecutorCoroutineDispatcherBase(), Closeable {
Roman Elizarovf04f51d2017-04-18 15:28:35 +030079 private val threadNo = AtomicInteger()
80
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080081 internal override val executor: ScheduledExecutorService = Executors.newScheduledThreadPool(nThreads) { target ->
Roman Elizarov731f0ad2017-02-22 20:48:45 +030082 PoolThread(this, target, if (nThreads == 1) name else name + "-" + threadNo.incrementAndGet())
Roman Elizarov3754f952017-01-18 20:47:54 +030083 }
84
Roman Elizarovd9ae2bc2017-10-20 17:36:56 +080085 /**
86 * Closes this dispatcher -- shuts down all threads in this pool and releases resources.
87 */
88 public override fun close() {
89 executor.shutdown()
Roman Elizarov3754f952017-01-18 20:47:54 +030090 }
91
Roman Elizarovf04f51d2017-04-18 15:28:35 +030092 override fun toString(): String = "ThreadPoolDispatcher[$nThreads, $name]"
Roman Elizarov3754f952017-01-18 20:47:54 +030093}