从syncExec返回变量的最佳方法是什么?
-
09-06-2019 - |
题
在我的 SWT Java 应用程序中,我经常希望从 Display.syncExec() 调用内部返回信息。到目前为止我发现的最好方法是:
final ArrayList<Integer> result = new ArrayList<Integer>();
GUI.display().syncExec(new Runnable(){ public void run() {
MessageBox mb = /* ... */;
/* set up messagebox */
result.add(mb.open());
}});
if (SWT.OK == result.get(0)) { /* ... */ }
我认为这是允许的,因为 ArrayList 是线程安全的,但是我应该使用更好的容器,或者更简单的方法吗?
解决方案
ArrayList
不是线程安全的. 。您可以获得线程安全的 List
和 Collections.synchronizedList
. 。然而,使用一个更简单的 AtomicInteger
在你的情况下或 AtomicReference
在更一般的情况下。
final AtomicInteger resultAtomicInteger = new AtomicInteger();
Display.getCurrent().syncExec(new Runnable() {
public void run() {
MessageBox mb = /* ... */;
/* set up messagebox */
resultAtomicInteger.set(mb.open());
}});
if (SWT.OK == resultAtomicInteger.get()) { /* ... */ }
其他提示
我刚刚解决了这个问题,我的第一次尝试是类似的 - 所需类型项目的数组或列表。但过了一会儿我做了这样的事情:
abstract class MyRunnable<T> implements Runnable{
T result;
}
MyRunnable<Integer> runBlock = new MyRunnable<Integer>(){
MessageBox mb = /* ... */;
/* set up messagebox */
result = mb.open();
}
GUI.display().syncExec(runBlock);
runBlock.result; //holds a result Integer
它更加整洁并删除了多余的变量。
顺便提一句。我真正的第一次尝试是使用 UIThreadRunnable,但我不想依赖 SWTBot,所以我放弃了这个解决方案。在我制定了自己的解决方案后,我发现他们在那里使用了类似的解决方案。
数组列表是 不是 线程安全。来自相关 Java文档:
请注意,此实现不同步。如果多个线程同时访问阵列列表实例,并且至少一个线程会在结构上修改列表,则必须在外部同步。
如果您需要 List 的线程安全实现,JDK 中(至少)提供了两个:CopyOnWriteArrayList 和 Vector。
您可以使用 Integer[1] 数组使其更加简洁,但我认为它不能直接从匿名内部类内部更新非最终变量。
final Integer[] result = new Integer[1];
我认为您必须将结果声明为最终结果(但该更改不会影响您的代码)。由于当前线程会阻塞,直到内部线程完成为止,我认为您不需要担心同步(但您可能需要使变量违反以便您看到结果)。
如果这种情况经常发生,您最好在流程和视图之间使用订阅/通知模型。您的视图订阅应触发该消息框的事件,并在满足条件时收到通知。