从Eclipse中的asyncExec中获取返回值的最佳方法是什么?

时间:2008-12-10 01:05:56

标签: eclipse eclipse-plugin anonymous-class

我正在编写Eclipse插件,并且经常出现这样的情况:正在运行的Job需要暂停一段时间,在UI线程上异步运行并恢复。

所以我的代码通常看起来像:

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!

一种方法是让整个Job类都有一些字段。另一种方法是使用自定义类(而不是匿名类,并使用其结果数据字段等。 什么是最好,最优雅的方法?

3 个答案:

答案 0 :(得分:8)

我认为上面的容器是“正确的”选择。它也可以是类型安全的通用化。在这种情况下的快速选择是最终的数组习语。诀窍是从Runnable引用的任何局部变量必须是最终的,因此不能修改。因此,您使用单个元素数组,其中数组是final,但可以修改数组的元素:

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]);

同样,对于那些您拥有匿名类并希望在不定义特定Container类的情况下为其提供结果的情况,这是“快速”解决方案。

<强>更新 在我想到这一点后,我意识到这适用于回调在同一个线程中的监听器和访问者类型用法。但是,在这种情况下,Runnable在另一个线程中执行,因此无法保证在syncExec返回后实际看到结果。正确的解决方案是使用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());

所有线程都保证可以看到对AtomicReference值的更改,就像它被声明为volatile一样。详细描述了here

答案 1 :(得分:4)

您可能不应该假设在Runnable调用返回时async asyncExec将完成。

在这种情况下,您正在考虑将结果推送到侦听器/回调(可能是Command模式),或者如果您希望稍后在同一方法中使用结果,请使用{{{ 1}}。

答案 2 :(得分:0)

好吧,如果它是同步的,你可以在run()方法外面拥有某种价值持有者。

经典是:

final Container container = new Container();
Display display = Display.getDefault();
display.syncExec(new Runnable()
{
  public void run()
  {
    container.setValue("foo");
  }
}
System.out.println(container.getValue());

容器只是:

public class Container {
  private Object value;
  public Object getValue() {
    return value;
  }
  public void setValue(Object o) {
    value = o;
  }
}

这当然是搞笑和狡猾(更狡猾的是创建一个新的List然后设置并获得第一个元素)但syncExec方法阻止所以没有什么不好的。

除非有人稍后回来并将其asyncExec() ...