Was ist der beste Weg, Variablen aus einer syncExec zurückzukehren?
-
09-06-2019 - |
Frage
In meinem SWT Java App möchte ich oft Informationen zurück aus dem Inneren eines Display.syncExec () -Aufruf. Der beste Weg, die ich gefunden habe, so weit dies zu tun ist:
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)) { /* ... */ }
Ich denke, das ist erlaubt, da Arraylist Thread-sicher ist, aber gibt es einen besseren Behälter wir verwenden sollen, oder ein einfacherer Weg, zusammen?
Lösung
ArrayList
ist nicht Thread-sicher . Sie können eine Thread-sichere List
mit Collections.synchronizedList
. Es ist jedoch viel einfacher, einen AtomicInteger
in Ihrem Fall oder AtomicReference
in einem allgemeineren Fall zu verwenden.
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()) { /* ... */ }
Andere Tipps
ich in Angriff genommen nur dieses Problems und mein erster Versuch war ähnlich - Array oder eine Liste der gewünschten Art Gegenstände. Aber nach einer Weile habe ich so etwas wie dies oben:
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
Es ist viel aufgeräumter und entfernt redundante Variablen.
BTW. Mein wirklich erster Versuch war UIThreadRunnable zu verwenden, aber ich habe nicht SWTBot Abhängigkeit wollte, so ließ ich diese Lösung. Nachdem ich meine eigene Lösung gemacht fand ich heraus, verwenden sie um eine ähnliche Arbeit da drin.
Arraylist ist nicht Thread-sicher. Aus den entsprechenden Javadoc :
Beachten Sie, dass diese Implementierung nicht synchronisiert. Wenn mehrere Threads Zugriff auf eine Arraylist-Instanz gleichzeitig, und mindestens eine der Threads ändert die Liste strukturell, muss synchronisiert werden nach außen.
Wenn Sie eine Thread-sichere Durchführung der Liste benötigen, gibt es (mindestens) zwei im JDK bereitgestellt. CopyOnWriteArrayList und Vector
Sie können einen Integer [1] Array verwenden, um es übersichtlicher zu machen, aber ich glaube nicht, dass direkt eine nicht endgültige Variable aus dem Innern einer anonymen inneren Klasse aktualisieren.
final Integer[] result = new Integer[1];
Ich dachte, dass Sie die Ergebnisse als endgültig erklären musste (aber diese Änderung würde der Code nicht beeinflussen). Da der aktuellen Thread blockiert, bis das innere Thema ist ich fertig glaube nicht, Sie Synchronisation kümmern müssen (aber Sie müssen möglicherweise die Variable machen verletzen, so dass Sie sehen das Ergebnis).
Wenn dies oft geschieht, besser Sie verwenden subscribe / notify Modell zwischen Prozess und Aussicht. Ihre Ansicht abonniert hat das Ereignis, das die Nachricht Feld auslösen soll und wird benachrichtigt, wenn die Bedingungen erfüllt werden.