3

Is it possible to execute a blocking coroutine call (one that returns a value) while also providing the thread to execute the call on (I don't want to use the main thread, which is the default)?

2 Answers 2

4

I suppose you are looking for async(context):

import kotlinx.coroutines.*

fun someCalc(): Int {
    println(Thread.currentThread().name) // Prints different thread
    Thread.sleep(500L)
    return 42
}

fun main() {
    val result = runBlocking {
        val deferred = async(Dispatchers.Default) {
            someCalc()
        }
        deferred.await()
    }
    println(result)
}

You can also use newSingleThreadContext() to create a context confined to a single thread and use it instead of Dispatchers.Default

EDIT: As @Rene said, there is a better solution:

val result = runBlocking {
        withContext(Dispatchers.Default) {
            someCalc()
        }
    }
Sign up to request clarification or add additional context in comments.

4 Comments

withContext would be easier.
OK, but say I created a thread using Thread(), how would I execute the call on that specific thread using this method?
You can't do it (unless you write your own dispatcher). What you CAN do is to create your own ExecutorService bound to a single thread, so this thread can be used both by coroutines and in your program. val executor = Executors.newSingleThreadExecutor() val context = executor.asCoroutineDispatcher() and then use withContext(context) to start a coroutine and executor.execute() to start any code you want to launch in this thread.
When you create a thread, you should pass a Runnable which will be executed in this thread. You can't change this Runnable after construction, so the Thread must be constructed and encapsulated by ExecutorService or Dispatcher, not by you.
1

If you just have a thread that's already running, and you have no control over the code it runs, then there is nothing you can do about it. The thread must be running a top-level event loop so you can inject the code to run from the outside.

If, by any chance, you have this kind of control, or you can decide which Runnable the thread will run to begin with, here's some pretty hacky code that manages to set up an event loop and submit a coroutine to it:

val myContextFuture = CompletableFuture<CoroutineContext>()
thread(name = "my-thread") {
    runBlocking {
        myContextFuture.complete(coroutineContext)
        coroutineContext[Job]!!.join()
    }
}
val myContext = myContextFuture.get()

Here's how you would run a coroutine on myContext:

val result = withContext(myContext) {
    println("Running on thread ${currentThread().name}")
    3
}
println("Result of the coroutine: $result")

I wouldn't recommend using this kind of code in production.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.