В моем приложении 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 является поточно-ориентированным нет. Из соответствующего Javadoc:
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.
Если вам нужна поточно-ориентированная реализация List, в JDK есть (как минимум) два: CopyOnWriteArrayList и Vector.
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()) { /* ... */ }
Вы могли бы использовать массив Integer [1], чтобы сделать его более кратким, но я не думаю, что он может напрямую обновлять неконечную переменную изнутри анонимного внутреннего класса.
final Integer[] result = new Integer[1];
Я думал, что вам нужно объявить результаты как окончательные (но это изменение не повлияет на ваш код). Поскольку текущий поток блокируется до тех пор, пока внутренний поток не будет завершен, я не думаю, что вам нужно беспокоиться о синхронизации (но вам может потребоваться заставить переменную нарушать, чтобы вы видели результат).
ИМО, это лучшее решение (другими словами, это то, что я сделал)
Если это происходит часто, вам лучше использовать модель подписки / уведомления между вашим процессом и представлением. Ваше представление подписывается на событие, которое должно вызвать это окно сообщения, и получает уведомление при выполнении условий.
Я только что решил эту проблему, и моя первая попытка была аналогичной - массив или список элементов желаемого типа. Но через некоторое время я придумал что-то вроде этого:
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, поэтому я отказался от этого решения. После того, как я сделал свое собственное решение, я обнаружил, что они используют аналогичную работу там.
Вам следует использовать Callable. Это похоже на Runnable, но допускает возврат. docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/…
Вы правы, но в данном случае это не имеет значения, потому что .syncExec блокируется.