Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I take advantage of Kotlin's Coroutines by using them in Java code?

What's my goal?

My goal is to be able to use Kotlin's Coroutine system from Java. I want to be able to pause mid-execution for a given amount of time, and then pick back up at that spot after the given amount of time has passed. From Java, I'd like to be able to execute tasks that allow pausing mid-execution without in an asynchronous fashion, such as:

//example 1
someLogic();
pause(3000L); //3 seconds
someMoreLogic();

//example 2
while(true) {
    someContinuedLogic();
    pause(10000L); //10 seconds
}

What's my issue?

As expected, I am able to execute coroutines perfectly fine from Kotlin, but when it comes to Java, it becomes tricky because the Java part of the code executes the entire block at once without any pauses, whereas the Kotlin block correctly pauses 1, and then 4 seconds.

What's my question?

Is it even possible to use Kotlin as a backbone for coroutines in Java? If so, what am I doing wrong? Below you can find the source code showing how I am attempting to use Kotlin's coroutines in Java.

KtScript Class

abstract class KtScript {

    abstract fun execute()

    fun <T> async(block: suspend () -> T): CompletableFuture<T> {
        val future = CompletableFuture<T>()
        block.startCoroutine(completion = object : Continuation<T> {
            override fun resume(value: T) {
                future.complete(value)
            }
            override fun resumeWithException(exception: Throwable) {
                future.completeExceptionally(exception)
            }
        })
        return future
    }

    suspend fun <T> await(f: CompletableFuture<T>): T =
            suspendCoroutine { c: Continuation<T> ->
                f.whenComplete { result, exception ->
                    if (exception == null)
                        c.resume(result)
                    else
                        c.resumeWithException(exception)
                }
            }

    fun pause(ms: Long): CompletableFuture<*> {
        //todo - a better pausing system (this is just temporary!)
        return CompletableFuture.runAsync {
            val currentMs = System.currentTimeMillis()
            while (System.currentTimeMillis() - currentMs < ms) {
                /* do nothing */
            }
        }
    }

}

Kotlin Execution Code

fun main(args: Array<String>) {
    ScriptTestKotlin().execute()
}

class ScriptTestKotlin : KtScript() {
    override fun execute() {
        println("Executing Kotlin script from Kotlin...")
        val future = async {
            await(pause(1000L))
            println("   1 second passed...")
            await(pause(4000L))
            println("   5 seconds passed...")
        }
        future.get() //wait for asynchronous task to finish
        println("Finished!")
    }
}

Kotlin Execution Results

Executing Kotlin script from Kotlin...
   1 second passed...
   5 seconds passed...
Finished!

Java Execution Code

public class ScriptTestJava extends KtScript {

    public static void main(String[] args) {
        new ScriptTestJava().execute();
    }

    @Override
    public void execute() {
        System.out.println("Executing Kotlin script from Java...");
        CompletableFuture<?> future = async(continuation -> {
            await(pause(1000L), continuation);
            System.out.println("    1 second passed...");
            await(pause(4000L), continuation);
            System.out.println("    5 seconds passed...");
            return continuation;
        });
        try {
            future.get(); //wait for asynchronous task to finish
        } catch(Exception e) {
            e.printStackTrace();
        }
        System.out.println("Finished!");
    }
}

Java Execution Results

Executing Kotlin script from Java...
    1 second passed...
    5 seconds passed...
Finished!

^^^ Unfortunately, the pauses are skipped in Java. ^^^

like image 982
Wonderlus Avatar asked Jan 10 '17 00:01

Wonderlus


People also ask

Can you use coroutines with Java?

Java, as slow adopter of new concepts is getting structured concurrency as part of the Loom project. This addition enables native support for coroutines (termed virtual threads) in Java.

Can I use Kotlin coroutines with Java?

We can consume this API from Kotlin coroutine to load two images and combine then asynchronously. The resulting function returns CompletableFuture<Image> for ease of use back from Java. Note that this module should be used only for integration with existing Java APIs based on CompletableFuture .

When should you not use coroutines?

Answer: a. You should not use them for any foreground task.

Are coroutines better than threads?

Coroutines are lighter than threads . Since they stack less . I.e coroutines don't have a dedicated stack . It means coroutine suspend execution by returning to the caller and the data that is required to resume execution is stored separately from the stack.


1 Answers

Kotlin coroutines are implemented with a compiler transformation to the code, which obviously can only be done by kotlinc.

So, no, Java cannot use Kotlin's coroutines mechanic since it is a compile-time feature.

like image 87
voddan Avatar answered Oct 18 '22 19:10

voddan