Skip to content

Commit e3cd41b

Browse files
authored
Use Dispatchers.Main as default delay source where applicable (#2974)
* Use Dispatchers.Main as default delay source where applicable It reduces the number of redundant threads in the system and makes time source predictable across Android/JavaFx applications Fixes #2972
1 parent fe9f50b commit e3cd41b

File tree

3 files changed

+20
-11
lines changed

3 files changed

+20
-11
lines changed

kotlinx-coroutines-core/common/src/Delay.kt

-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ public interface Delay {
5151
* Schedules invocation of a specified [block] after a specified delay [timeMillis].
5252
* The resulting [DisposableHandle] can be used to [dispose][DisposableHandle.dispose] of this invocation
5353
* request if it is not needed anymore.
54-
*
55-
* This implementation uses a built-in single-threaded scheduled executor service.
5654
*/
5755
public fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle =
5856
DefaultDelay.invokeOnTimeout(timeMillis, block, context)

kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,25 @@
44

55
package kotlinx.coroutines
66

7+
import kotlinx.coroutines.internal.*
78
import java.util.concurrent.*
89
import kotlin.coroutines.*
910

10-
internal actual val DefaultDelay: Delay = DefaultExecutor
11+
internal actual val DefaultDelay: Delay = initializeDefaultDelay()
12+
13+
private val defaultMainDelayOptIn = systemProp("kotlinx.coroutines.main.delay", true)
14+
15+
private fun initializeDefaultDelay(): Delay {
16+
// Opt-out flag
17+
if (!defaultMainDelayOptIn) return DefaultExecutor
18+
val main = Dispatchers.Main
19+
/*
20+
* When we already are working with UI and Main threads, it makes
21+
* no sense to create a separate thread with timer that cannot be controller
22+
* by the UI runtime.
23+
*/
24+
return if (main.isMissing() || main !is Delay) DefaultExecutor else main
25+
}
1126

1227
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
1328
internal actual object DefaultExecutor : EventLoopImplBase(), Runnable {

ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt

+4-8
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,18 @@ public sealed class JavaFxDispatcher : MainCoroutineDispatcher(), Delay {
3434

3535
/** @suppress */
3636
override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
37-
val timeline = schedule(timeMillis, TimeUnit.MILLISECONDS, EventHandler {
37+
val timeline = schedule(timeMillis, TimeUnit.MILLISECONDS) {
3838
with(continuation) { resumeUndispatched(Unit) }
39-
})
39+
}
4040
continuation.invokeOnCancellation { timeline.stop() }
4141
}
4242

4343
/** @suppress */
4444
override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle {
45-
val timeline = schedule(timeMillis, TimeUnit.MILLISECONDS, EventHandler {
45+
val timeline = schedule(timeMillis, TimeUnit.MILLISECONDS) {
4646
block.run()
47-
})
48-
return object : DisposableHandle {
49-
override fun dispose() {
50-
timeline.stop()
51-
}
5247
}
48+
return DisposableHandle { timeline.stop() }
5349
}
5450

5551
private fun schedule(time: Long, unit: TimeUnit, handler: EventHandler<ActionEvent>): Timeline =

0 commit comments

Comments
 (0)