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