【问题标题】:What's the best way to get a return value out of an asyncExec in Eclipse?从 Eclipse 中的 asyncExec 中获取返回值的最佳方法是什么?
【发布时间】:2008-12-10 01:05:56
【问题描述】:

我正在编写 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 类都有一些字段。另一种是使用自定义类(而不是匿名的,并使用其结果数据字段等)。 最好和最优雅的方法是什么?

【问题讨论】:

  • 您需要澄清“在 UI 线程上异步运行”语句,因为您的示例代码清楚地使用了 display.syncExec,这意味着您的作业线程将在 run() 中的代码执行时暂停显示线程。
  • 标题和问题文本是asyncExec,但示例代码有syncExec。那是两个截然不同的问题!是哪一个?

标签: eclipse eclipse-plugin anonymous-class


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    在这种情况下,您正在考虑将结果推送到侦听器/回调中(可能是命令模式),或者如果您确实希望稍后在相同的方法中获得结果,使用类似 @987654323 的东西@。

    【讨论】:

      【解决方案3】:

      好吧,如果它是同步的,那么您可以在 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()..

      【讨论】:

      • 问题中的示例代码正在使用 syncExec() 并且问题文本说“运行作业需要暂停一会儿,在 UI 线程上异步运行某些内容,然后恢复”。所以我认为这行得通。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-16
      • 1970-01-01
      相关资源
      最近更新 更多