Search code examples
multithreadingkotlinkotlinx.coroutines

Why doesn't Executor.asCoroutineDispatcher work like newFixedThreadPoolContext?


I thought these two lines would be equivalent execution wise:

val context1 = Executors.newFixedThreadPool(2).asCoroutineDispatcher()
val context2 = newFixedThreadPoolContext(2, "Fixed")

But when I use "context2" in the code below it works as expected, but "context1" acts like a single thread.

val context1 = Executors.newFixedThreadPool(2).asCoroutineDispatcher()

repeat(4) {
    launch {
        withContext(context1) {
            Thread.sleep(2000)
        }
    }
}

context1.close()

Expected: 2 threads will execute in parallel. The code should complete in 4 seconds, because to 2 threads sleep for 2 seconds and then repeat.

Actual: Only one thread executes and the "repeat" is executed serially, which takes 8 seconds to complete.

Is this a bug?

Or what is meant by this documentation found here?

If you need a completely separate thread-pool with scheduling policy that is based on the standard JDK executors, use the following expression: Executors.newFixedThreadPool().asCoroutineDispatcher().


Solution

  • After playing with the full code example:

    import kotlinx.coroutines.*
    import java.util.concurrent.Executors
    
    fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
    
    
    fun main() = runBlocking {
        val context1 = Executors.newFixedThreadPool(2).asCoroutineDispatcher()
        val context2 = newFixedThreadPoolContext(2, "Fixed")
    
        repeat(4) {
            launch {
                withContext(context1) {
                    log("Start sleep $it")
                    Thread.sleep(2000)
                    log("Finished sleep $it")
                }
            }
        }
    
    //    context1.close()
    }
    

    I discovered the problem is with the "context1.close()". If I comment out the "context1.close()" it works correctly. My guess is that the "launch" calls aren't blocking, so the "context1.close()" gets executed before the "withContext" executes on the other threads. I would have assumed that would cause an error, but it appears to just make it a single thread.