Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to get a return value out of an asyncExec in Eclipse?

I am writing Eclipse plugins, and frequently have a situation where a running Job needs to pause for a short while, run something asynchronously on the UI thread, and resume.

So my code usually looks something like:

Display display = Display.getDefault();
display.syncExec(new Runnable() {
    public void run() {
                // Do some calculation
                // How do I return a value from here?
    }
});
// I want to be able to use the calculation result here!

One way to do it is to have the entire Job class have some field. Another is to use a customized class (rather than anonymous for this and use its resulting data field, etc. What's the best and most elegant approach?

like image 811
Uri Avatar asked Dec 10 '08 01:12

Uri


2 Answers

I think the Container above is the "right" choice. It could be also be genericized for type safety. The quick choice in this kind of situation is the final array idiom. The trick is that a any local variables referenced from the Runnable must be final, and thus can't be modified. So instead, you use a single element array, where the array is final, but the element of the array can be modified:

final Object[] result = new Object[1];
Display display = Display.getDefault();
display.syncExec(new Runnable()
{
  public void run()
  {
    result[0] = "foo";
  }
}
System.out.println(result[0]);

Again, this is the "quick" solution for those cases where you have an anonymous class and you want to give it a place to stick a result without defining a specific Container class.

UPDATE After I thought about this a bit, I realized this works fine for listener and visitor type usage where the callback is in the same thread. In this case, however, the Runnable executes in a different thread so you're not guaranteed to actually see the result after syncExec returns. The correct solution is to use an AtomicReference:

final AtomicReference<Object> result = new AtomicReference<Object>();
Display display = Display.getDefault();
display.syncExec(new Runnable()
{
  public void run()
  {
    result.set("foo");
  }
}
System.out.println(result.get());

Changes to the value of AtomicReference are guaranteed to be visible by all threads, just as if it were declared volatile. This is described in detail here.

like image 101
Dave Ray Avatar answered Nov 15 '22 19:11

Dave Ray


You probably shouldn't be assuming that the async Runnable will have finished by the time the asyncExec call returns.

In which case, you're looking at pushing the result out into listeners/callbacks (possibly Command pattern), or if you do want to have the result available at a later in the same method, using something like a java.util.concurrent.Future.

like image 22
jamesh Avatar answered Nov 15 '22 20:11

jamesh