Continuations supersede SwingWorker and Foxtrot
SwingWorker is a pretty complete approach to off-event-queue execution, but clumsy syntactically:
http://download.java.net/jdk6/docs/api/javax/swing/SwingWorker.html
FoxTrot improves the API a bit for the simple cases but relies on the funky trick of pushing a new event thread:
http://foxtrot.sourceforge.net/docs/worker.php
Turns out that using continuations you can make the simple cases even simpler. Try running the following using Mustang's jrunscript -f demo.js:
function cont() {
return new Continuation();
}
function offEQ(execsvc) {
var c = cont();
if (c instanceof Continuation) {
execsvc.submit(
new java.lang.Runnable({
run:
function() {
c();
}
})
);
return true;
} else {
return false;
}
}
function onEQ() {
var c = cont();
if (c instanceof Continuation) {
java.awt.EventQueue.invokeLater(
function() {
c();
});
return true;
} else {
return false;
}
}
function showThread() {
print(java.lang.Thread.currentThread());
}
var swing = Packages.javax.swing;
var frame = new swing.JFrame("Demo");
frame.setLayout(java.awt.FlowLayout());
var button = new swing.JButton("Start");
var es = java.util.concurrent.Executors.newSingleThreadExecutor();
button.addActionListener(
function(event) {
field.setText("clicked");
button.setEnabled(false);
for (var i = 0; i < 10; i++) {
field.setText("sleeping #" + i);
showThread();
if (offEQ(es)) return;
showThread();
java.lang.Thread.sleep(1000);
if (onEQ()) return;
showThread();
}
field.setText("done");
button.setEnabled(true);
});
frame.add(button);
var field = new swing.JTextField(20);
frame.add(field);
field.setText("idle");
field.setEditable(false);
frame.setDefaultCloseOperation(3);
frame.pack();
frame.setVisible(true);
java.lang.Thread.sleep(9999999);
Unfortunately continuations are not available in Java itself, only in the bundled Rhino JavaScript. Some day...
Posted at 12:00AM Feb 05, 2006 by jglick in Sun | Comments[5]
Posted by Jesse Glick on February 20, 2006 at 01:08 PM EST #
importPackage(java.util); function enumeration(impl) { var next; var full = false; var end = false; var c1, c2; function peek() { if (end || full) { return; } if (c1 == null) { c1 = new Continuation(); impl(function(val) { next = val; full = true; c2 = new Continuation(); c1(); }); end = true; } else { c2(); } } return new Enumeration({ hasMoreElements: function() { peek(); return !end; }, nextElement: function() { peek(); full = false; return next; } }); } var e = enumeration(function(yield) { for (i = 0; i < 10; i++) { yield(i); } }); println(Collections.list(e));Posted by Jesse Glick on May 30, 2006 at 03:40 PM EDT #
import java.util.*; interface Yielder<T> { void yield(T); } interface Generator<T> { void generate(Yielder<T> y); } static <T> Enumeration<T> generatorEnumeration(final Generator<T> g) { return new Enumeration<T>() { T next; boolean full, end; Continuation<Void> c1, c2; void peek() { if (end || full) { return; } if (c1 == null) { c1 = new return; g.generate( new Yielder<T>() { public void yield(T val) { next = val; full = true; c2 = new return; c1.return; } }); end = true; } else { c2.return; } } public boolean hasMoreElements() { peek(); return !end; } public T nextElement() { peek(); if (end) { throw new NoSuchElementException(); } assert full; full = false; return next; } }; } Enumeration<Integer> e = generatorEnumeration( new Generator<Integer>() { public void generate(Yielder<Integer> y) { for (int i = 0; i < 10; i++) { y.yield(i); } } }); System.out.println(Collections.list(e));Posted by Jesse Glick on May 30, 2006 at 03:52 PM EDT #
import java.util.*; public abstract class GeneratorEnumeration<T> implements Enumeration<T> { private T next; private boolean full, end; private Continuation<Void> c1, c2; private void peek() { if (end || full) { return; } if (c1 == null) { c1 = new return; generate(); end = true; } else { c2.return; } } public final boolean hasMoreElements() { peek(); return !end; } public final T nextElement() { peek(); if (end) { throw new NoSuchElementException(); } assert full; full = false; return next; } protected final void yield(T val) { next = val; full = true; c2 = new return; c1.return; } protected abstract void generate(); } Enumeration<Integer> e = new GeneratorEnumeration<Integer>() { protected void generate() { for (int i = 0; i < 10; i++) { yield(i); } } }; System.out.println(Collections.list(e));Posted by Jesse Glick on May 30, 2006 at 04:05 PM EDT #
Posted by Aviad Ben Dov on July 30, 2007 at 03:10 PM EDT #