Qual è il modo migliore per restituire variabili da un syncExec?
-
09-06-2019 - |
Domanda
Nella mia app Java SWT desidero spesso restituire informazioni dall'interno di una chiamata Display.syncExec().Il modo migliore che ho trovato finora per farlo è:
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)) { /* ... */ }
Penso che ciò sia consentito perché ArrayList è thread-safe, ma esiste un contenitore migliore che dovrei utilizzare o un modo del tutto più semplice?
Soluzione
ArrayList
non è thread-safe.È possibile ottenere un file thread-safe List
con Collections.synchronizedList
.Tuttavia, è molto più semplice utilizzare un file AtomicInteger
nel tuo caso o AtomicReference
in un caso più generale.
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()) { /* ... */ }
Altri suggerimenti
Ho appena affrontato questo problema e il mio primo tentativo è stato simile: array o elenco di elementi del tipo desiderato.Ma dopo un po' ho inventato qualcosa del genere:
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
È molto più ordinato e rimuove le variabili ridondanti.
A proposito.Il mio primo vero tentativo è stato utilizzare UIThreadRunnable, ma non volevo la dipendenza SWTBot, quindi ho abbandonato questa soluzione.Dopo aver creato la mia soluzione, ho scoperto che usano un lavoro simile lì dentro.
ArrayList è non thread-safe.Dal pertinente Javadoc:
Si noti che questa implementazione non è sincronizzata.Se più thread accedono a un'istanza di ArrayList contemporaneamente e almeno uno dei thread modifica strutturalmente l'elenco, deve essere sincronizzato esternamente.
Se hai bisogno di un'implementazione thread-safe di List, ce ne sono (almeno) due fornite nel JDK:CopyOnWriteArrayList e Vector.
Potresti usare un array Integer[1] per renderlo più conciso ma non penso che possa aggiornare direttamente una variabile non finale dall'interno di una classe interna anonima.
final Integer[] result = new Integer[1];
Pensavo che dovessi dichiarare i risultati come finali (ma quella modifica non avrebbe influenzato il tuo codice).Poiché il thread corrente si blocca fino al completamento del thread interno, non penso che tu debba preoccuparti della sincronizzazione (ma potresti dover violare la variabile in modo da vedere il risultato).
Se ciò accade spesso, è meglio utilizzare il modello di iscrizione/notifica tra il processo e la visualizzazione.La tua vista si iscrive all'evento che dovrebbe attivare quella finestra di messaggio e ricevere una notifica quando le condizioni sono soddisfatte.