(Lack of) Coroutines in Java
My current work project involves lots of small bits of code talking to each other asynchronously and requesting data from a distributed network. This means that when my code goes to retrieve a piece of data, it may be returned quickly, slowly, or not at all. Because of this uncertainty, we wouldn’t want to hold up other parts of the code while waiting for data, and so we want to put the requesting code aside and just come back to it later if and when the data arrives.
The current state of the art looks a bit like this–effectively a callback-based state machine:
Snippet establishPreference = new Snippet() {
// called when the result of requestData is available
public void dataReceivedCallback(Data d) {
if (d.getValue("likes_marmalade")) {
serveToast.requestData("marmalade");
} else {
serveBagel.requestData("cream cheese");
}
}
}
Snippet serveToast = new Snippet() {
public void dataReceivedCallback(Data d) {
spreadOnToast(d.getValue("spoonful_of_substance"));
}
}
Snippet serveBagel = new Snippet() {
public void dataReceivedCallback(Data d) {
spreadOnBagel(d.getValue("spoonful_of_substance"));
}
}
To kick off this process, you would call:
establishPreference.requestData("Joe Hughes");
And then depending on whether I liked marmalade or not, I would eventually get served either toast with marmalade or a bagel with cream cheese.
This works fine, but you can see how it could easily get convoluted once you do any kind of serious branching or looping. For the sake of easier creation and maintenance of these things, I’d really like to be able to express these operations more like this:
Data customer = requestData("Joe Hughes");
if (customer.getValue("likes_marmalade")) {
Data topping = requestData("marmalade");
spreadOnToast(topping.getValue("spoonful_of_substance"));
} else {
Data topping = requestData("cream cheese");
spreadOnBagel(topping.getValue("spoonful_of_substance"));
}
When you put it that way, it’s much easier to see what’s going on. The problem is that in order for this to work, you have to be able to pause this block of code whenever you go off to do a requestData() call, and then restart it with result when you receive it. It turns out that what I’m describing is a somewhat obscure programming language construct called a coroutine.
Unfortunately, not many modern programming languages natively support coroutines. Python does, somewhat (through Stackless and the new Generator construct). Ruby seems to. Io and Lua do. Java, however, doesn’t.
I’ve certainly been able to use threads to make things that look like coroutines:
public abstract class PseudoCoroutine
implements DataListener, Runnable {
private Data response = null;
/**
* This method starts a thread to run the specified task.
*
* @param task the PseudoCoroutine subclass to be run.
*/
public static void doTask(PseudoCoroutine task) {
t = new Thread(task, task.getClass().getName());
t.start();
}
/**
* This is a callback method from the DataListener interface
* provided to the DataService to call when it has retrieved the requested data.
*
* @param d the data received
*/
synchronized public void dataReceived(Data d) {
this.response = d;
notifyAll();
}
/**
* Provides a delayed-synchronous way to perform a data request.
* This method call will block until the response
* is received from the server.
*
* @param dataID the ID of the data to be requested.
* @return A Data object corresponding to the requested dataID.
* @throws InterruptedException
*/
protected Data requestData(String dataID) throws InterruptedException {
// second parameter is used to pass this.dataReceived() as a callback
DataService.getInstance().requestData(dataID, this);
synchronized (this) {
while (this.response == null) {
wait();
}
}
return this.response;
}
// to make this a Runnable that can be passed to a thread
public void run() {
taskBody();
}
/**
* This is where the PseudoCoroutine subclass should perform its task.
*/
public abstract void taskBody();
}
This class lets me just use the code I had written above:
private class ServeBreakfastBread extends PseudoCoroutine {
private String customerID;
public ServeBreakfastBread(String customerID) {
this.customerID = customerID;
}
public void taskBody() {
Data customer = requestData(customerID);
if (customer.getValue("likes_marmalade")) {
Data topping = requestData("marmalade");
spreadOnToast(topping.getValue("spoonful_of_substance"));
} else {
Data topping = requestData("cream cheese");
spreadOnBagel(topping.getValue("spoonful_of_substance"));
}
}
}
...
PseudoCoroutine.doTask(new ServeBreakfastBread("Joe Hughes"));
This works fine, except that each of these things now requires an OS thread, with their attendant limitations (good luck getting more than a few thousand on a desktop VM). I’d also like to have the ability for several of these coroutines to be able to operate on common state information without lots of synchronization hassle, which I can’t do if each coroutine lives in its own thread.
So, where to now? Maybe I can embed another language interpreter within my Java system and express the coroutines in that. Unfortunately, Jython doesn’t support Generators yet. I’ll have to look into LuaJava and JRuby to see if they have anything to offer.
October 10th, 2005 at 12:19 pm
Hi joe,
I’m looking for the same sort of things.
I have been “rewriting” a scheduler to be able to explicitly manage the activation of the threads of my application, but I am facing the limit on the number of threads that a jvm can support.
Did you go any further ? I don’t know what would be the way to implement coroutine in Java and what would be the cost in term of execution time.
Thanks for your answer.
Regards.
October 18th, 2005 at 4:01 pm
Malos,
Basically, if you’re running into the JVM’s thread limits, you’ll have to write your own scheduler to manage execution. The coroutines won’t help performance—I’m interested in them as a way to improve the programming idioms of code that doesn’t use real threads.
November 25th, 2005 at 4:13 pm
Hi Joe,
I am thinking whether it is possible with any other design to avoid a new thread creations for each method call and use the same thread.
I mean for each call, its creating a new Thread, instead with any other design style is it possible to use one single thread only.(using Wait and Notify and another extra supporting Thread).
regards,
Kishore.
pra_kis @ yahoo
February 20th, 2006 at 1:12 am
Hi Joe,
Is there any reason why you can’t use java.nio.channels? I thought they were created for just this purpose. You get multiplexed non-blocking I/O which doesn’t rely on threads, so it scales better.
http://java.sun.com/j2se/1.4.2/docs/api/java/nio/channels/package-summary.html