does-work-in-JVM for coroutines
While @Synchronized
is not supported outside of JVM, see 'synchronized' Is Not Supported. Experimentally (on MAC OS) It does in fact work within the JVM.
Here is an example:
GT-Sandbox-Snapshot: With @Synchronized the count is a expected; Without its not.
Code
package com.glassthought.sandbox
import gt.sandbox.util.output.Out
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis
var sharedCounter = 0 // Shared resource
val out = Out.standard()
@Synchronized
fun incrementSharedCounter(){
sharedCounter++
}
fun main() = runBlocking {
val coroutineCount = 5
val iterationsPerCoroutine = 1000000
val timeTaken = measureTimeMillis {
val jobs = List(coroutineCount) { idx ->
launch(CoroutineName("coroutine-$idx") + Dispatchers.IO) {
out.info("Starting coroutine $idx")
repeat(iterationsPerCoroutine) {
incrementSharedCounter()
}
}
}
jobs.forEach { it.join() } // Wait for all coroutines to finish
}
out.info("Expected counter value: ${coroutineCount * iterationsPerCoroutine}")
out.info("Actual counter value: $sharedCounter")
out.info("Time taken: $timeTaken ms")
}
Command to reproduce:
gt.sandbox.checkout.commit 69e54170ef0e40dc3a55 \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"
Recorded output of command:
[elapsed: 48ms][⓹/tname:DefaultDispatcher-worker-6/tid:25][coroutine:coroutine-3] Starting coroutine 3
[elapsed: 48ms][⓺/tname:DefaultDispatcher-worker-4/tid:23][coroutine:coroutine-4] Starting coroutine 4
[elapsed: 48ms][⓷/tname:DefaultDispatcher-worker-3/tid:22][coroutine:coroutine-1] Starting coroutine 1
[elapsed: 48ms][⓶/tname:DefaultDispatcher-worker-1/tid:20][coroutine:coroutine-0] Starting coroutine 0
[elapsed: 48ms][⓸/tname:DefaultDispatcher-worker-2/tid:21][coroutine:coroutine-2] Starting coroutine 2
[elapsed: 217ms][🥇/tname:main/tid:1][coroutine:unnamed] Expected counter value: 5000000
[elapsed: 217ms][🥇/tname:main/tid:1][coroutine:unnamed] Actual counter value: 5000000
[elapsed: 218ms][🥇/tname:main/tid:1][coroutine:unnamed] Time taken: 190 ms
This makes sense as if @Synchronized
works by making sure only one thread can enter the block, then the co-routines must execute on some thread at some point. And that is where the @Synchronized
takes effect./