X

Sundararajan's Weblog

  • Java |
    January 19, 2007

Continuations for Java

Continuation
is an object that represents the execution state of a program
at a certain point. We can use continuation to restart the execution
from the point stored in it.

How about continuations for the Java platform? There are atleast two different implementations of continuations:

I've experimented with javaflow. I checked out javaflow sources
under, say %JAVAFLOW_HOME% directory (no pre-built binaries available in the site).
I tried building it by maven. But failed ... because I need
parent pom file! (never mind if you don't understand that -- that is just a build
step). Because I am only interested in playing with continuation,
I ignored maven build. I just created a NetBeans
project and added all source directories of javaflow. I copied
dependent libraries (ant.jar, commons-logging-1.0.4.jar, junit-3.8.2.bar, junit-addons-1.4.jar -- I just copied the versions that I had -- check for proper dependency or use maven to build!)
under %JAVAFLOW_HOME%\\lib directory and added all jars under this
directory to netbeans project. I managed to build and produce
javaflow.jar under %JAVAFLOW_HOME%\\dist. The following is a simple
program that uses continuations [this is just slightly modified
version of the one in the javaflow
tutorial
]


import org.apache.commons.javaflow.\*;
class Test {
static class MyRunnable implements Runnable {
public void run() {
System.out.println("run started!");
for( int i=0; i < 10; i++ ) {
echo(i);
}
}
private void echo(int x) {
System.out.println("echo " + x);Continuation.suspend();
}
}
public static void main(String[] args) {
System.out.println("main started");
Continuation c = Continuation.startWith(new MyRunnable());
System.out.println("in main after continuation return");
while (c != null) {
c = Continuation.continueWith(c);
System.out.println("in main");
}
}
}

The output of the above program is shown below:
main started
run started!
echo 0
in main after continuation return
echo 1
in main
echo 2
in main
echo 3
in main
echo 4
in main
echo 5
in main
echo 6
in main
echo 7
in main
echo 8
in main
echo 9
in main
in main

The execution seems to "flip-flop" between Test.main and
Test.MyRunnable.echo methods!. No, there are no
multiple threads here. Single thread of execution produces
the output shown above. That is because of continuation. If you don't get that,
you may want to read this.

The steps used in build, run the above program:

  • I compiled the above program using the following command:
    javac -cp %JAVAFLOW_HOME%\\dist\\javaflow.jar Test.java

    The above step created two .class files - Test.class, Test$MyRunnable.class.
  • Continuation implementation works by bytecode instrumenting of
    the .class files of your application. Either you can instrument the program ahead of
    execution (during build) or do it at runtime using a special class loader. This
    being a simple hack exercise for learning, I instrumented these .class files using the following commands:

    java -cp .;%JAVAFLOW_HOME%\\dist\\javaflow.jar;%JAVAFLOW_HOME%\\lib\\\* RewriteTool <Test.class >mTest.class
    java -cp .;%JAVAFLOW_HOME%\\dist\\javaflow.jar;%JAVAFLOW_HOME%\\lib\\\* RewriteTool <Test$MyRunnable.class >mTest$MyRunnable.class
    move mTest.class Test.class
    move mTest$MyRunnable.class Test$MyRunnable.class

    Actually, there is a better way to pre-instrument .class files for
    continuation support: there is a javaflow ant task.
    (the ones that use continuations need to be instrumented. You can leave the other jar files)

  • I ran the program with the following command:
    java -cp .;%JAVAFLOW_HOME%\\dist\\javaflow.jar;%JAVAFLOW_HOME%\\lib\\\* Test

As you may know already, JDK 6 includes javax.script API
and Mozilla Rhino based
JavaScript engine. There is continuation support in Rhino. But then, that is
a topic for another blog entry :-)

Join the discussion

Comments ( 10 )
  • Nico Friday, January 19, 2007
    Huh. It had not occurred to me that one could transform the bytecode generated by javac (and other compilers) to support continuations. The instrumentation by custom class loader idea is very elegant.
  • Doug Daniels Friday, January 19, 2007
    Continuations are an extremely interesting way to preserve and pass on the state of running processes.
    I know for the most part continuations and the java scripting framework usage has been focused on distributed enterprise programming (or at least what I've seen).
    I was wondering if anyone has done any work integrating the Java scripting framework with game development on the Java platform.
    Many commercial games expose their game engines through easy to use scripting frameworks. I think the fact that Java 6 comes with the ability to basically plug in any scripting language is HUGE!!
    Also continuations, and coroutines are very interesting concurrency topics, even if they're just being used to fake out concurrent processes.
    You could imagine scriptable game entities and AI running around in your distributed game engine using continuations to suspend their execution and transfer themselves to another server to then continue executing.
    I've done some preliminary research and there's alot of good articles on game scripting and concurrency.
    Check out this article about stackless python:
    http://harkal.sylphis3d.com/2005/08/10/multithreaded-game-scripting-with-stackless-python
    Also I wrote a post on concurrency and game scripting:
    http://daniels.net/ddanielsblog/2006/11/24/simulated-concurrent-game-scripting-using-coroutines/
  • A. Sundararajan Friday, January 19, 2007

    Hi Nico: Yes, doing bytecode instrumentation at classload is interesting. javaflow has ContinuationClassLoader class for this.

    Hi Doug Daniels: It is great that scripting gets attention in the Java platform. Thanks for the references on scripting with games! I'll check out these resources.


  • Doug Daniels Saturday, January 20, 2007
    Sorry I gave an invalid link to my blog posting, I forgot a "d" in http://ddaniels.net haha.
    Here's the correct article:
    Simulated Concurrent Game Scripting using coroutines
    I discuss how the Java 6 scripting framework could provide interesting solutions to adding concurrency to game simulations which for the most part are usually run in a single threaded serial manner.
  • Ranjan Bhandari Monday, January 22, 2007
    Another nice article...thx....I love to see these syntatic suger supported by language itself. I loved the idea of closure, CPS in pure functional programming languages. However, I am little bit doubtful how these wonderful ideas can be supported in imperative programming like java though. In the process of supporting( i would rather say competing with other languages)we may not end up with the language which is rather bloated and ugly?
  • Ranjan Bhandari Monday, January 22, 2007
    Another nice article...thx....I love to see these syntatic suger supported by language itself. I loved the idea of closure, CPS in pure functional programming languages. However, I am little bit doubtful how these wonderful ideas can be supported in imperative programming like java though. In the process of supporting( i would rather say competing with other languages)we may not end up with the language which is rather bloated and ugly.
  • Jochen &quot;blackdrag&quot; Theodorou Wednesday, January 24, 2007
    javaflow is surely an interesting work, but don't I need to instrument all methods that are part of the stack to get this working? In your example this is run, echo and even main. That limits the usage of such continuations to a smaller amount of classes and excludes exchangeable frameworks. At last whenever I have to give some kind of action into the framework. But for many other things, this might do the job.
  • A. Sundararajan Wednesday, January 24, 2007

    Hi Ranjan Bhandari: If continuations are implemented as API (like it is done with javaflow or RIFE) there is no change in Java programming language anyway - and therefore no bloating language. Also, if Java VM would support continuations at VM level (as VM primitive so that bytecode instrumentation is not needed), that would help implementing languages that need continuation primitive (like Scheme). Alternate languages on top of JVM is interesting by itself.

    Hi Jochen "blackdrag" Theodorou": Yes you are right. We need to instrument all the classes whose methods will appear on the stack. Both javaflow and RIFE-continuations implement continuations by bytecode instrumentation. Yes, I agree - the solution is to support continuations at JVM level. But then you may want to read http://blogs.sun.com/gbracha/entry/will_continuations_continue as well.

  • Jochen &quot;blackdrag&quot; Theodorou Thursday, January 25, 2007
    My point wasn't that continuations at the JVM level are the only solution here. I have read http://blogs.sun.com/gbracha/entry/will_continuations_continue and that does not satisfy me. I think I know a way to simulate continuations for Groovy, that doesn't need instrumentation, that doesn't need changes in the JVM and that can be used transparently. But it is not going to be efficient and increases the deadlocking danger extremly. If the Java API would provide a way to have lightweight Threads, this would be more easy and more efficient.
  • A. Sundararajan Thursday, January 25, 2007
    Hi Jochen: It is interesting that you have some other technique (other than BCI) to do continuation. That sounds very interesting. Will you please point me to your blog entry/article on the same? Thanks.
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha
Oracle

Integrated Cloud Applications & Platform Services