29
votes

Is there a good implementation of continuations in Java?

If so, what is the overhead like? The JVM wasn't designed with these sort of things in mind, right? So is this kind of going against the grain?

11

11 Answers

13
votes

See Apache Javaflow http://commons.apache.org/sandbox/javaflow/

It's the only continuation package for java that's actively under development. The other one, RIFE, I'm not sure which state it's in.

7
votes

Jetty has continuation support. There is further discussion and some samples at DZone.

I can't advise on the efficiencies or otherwise, other than to say that the Mortbay team always appear concious of such issues. There will most likely be a discussion of implementation trade-offs somewhere on the Jetty site.

2
votes

If I understand this correctly, I suppose the obvious problem involves unwinding the stack with closure instances active. I suppose a language with lexical scope could in theory figure out that a child frame may create a closure instance, identify those intermediate frames that are referenced, and then it could malloc those frames instead of just pushing them on the stack.

For that matter, a compiler could malloc all frames or all parent frames of a closure referencing a non-globally-bound object.

Summary

I don't think the JVM restricts closures any more than a real machine, it's just that they fight the general stack paradigm and so they usually get punted.

2
votes

If you don't mind implicit continuations, Kilim is a great option. It works by processing annotated methods and generating the continuations in bytecode for you. Obviously it does a lot more since it's a framework, but if you want the (excellent) performance of thread-safe continuations, it's worth a look.

2
votes

Since Java 8, there is now a CompletableFuture<T> class which supports continuations and more functional / reactive programming approaches.

Consider the following example, where a Class offers a downloadAndResize method:

public CompletableFuture<Image> downloadAndResize(String imageUrl, int width, int height) {
    return CompletableFuture
        .supplyAsync(() -> downloadImage(imageUrl))
        .thenApplyAsync(x -> resizeImage(x, width, height));
}

private Image downloadImage(String url){
    // TODO Download the image from the given url...
}

private Image resizeImage(Image source, int width, int height){
    // TODO Resize the image to w / h
}

Usage of the above method could look like:

CompletableFuture<Image> imagePromise = downloadAndResize("http://some/url", 300, 200);

imagePromise.thenAccept(image -> {
    // Gets executed when the image task has successfully completed

    // do something with the image

});
1
votes

Another strong competitior has appeared recently.

Quasar uses forked from Matthias Mann's implementation of java continuations to provide higher level features like lightweight threads, Erlang-like actors and Go-like coroutines and channels.

There are many benchmarks and detailed introductions in the Quasar Blog.

There is also ready-to-use integration named Comsat aimed to help easily building performant web services based on continuations machinery under the hood.

Quasar also provides a nice Kotlin API that was featured on recent JetBrains webinar Quasar: Efficient and Elegant Fibers, Channels and Actors.

Everything mentioned is open-source and free to use.

See also http://blog.paralleluniverse.co/2015/08/07/scoped-continuations/


Update

Quasar's experience was later used as foundation for the Loom Project which aims to bring continuations support directly into JVM sometime past Java 11.

It's under active development now and already has a working alpha prototype.

1
votes

Consider also Kotlin Coroutines.

It's implemented via potentially more performant CPS transformations (still stackful) and can use any async executor under the hood like ForkJoinPool or Quasar integration.

Comes with handy guided library.

Beware of some tooling and reflection pitfalls.

0
votes

Scala also runs on JVM. So it might be relevant.

What are Scala continuations and why use them?

In addition Scala has somewhat similar async/await feature:

http://docs.scala-lang.org/sips/pending/async.html