Как лучше всего вернуть переменные из syncExec?

В моем приложении 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 является потокобезопасным, но есть ли лучший контейнер, который я должен использовать, или более простой способ в целом?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
1 393
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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.

Вы правы, но в данном случае это не имеет значения, потому что .syncExec блокируется.

SCdF 17.09.2008 00:23
Ответ принят как подходящий

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];

Я думал, что вам нужно объявить результаты как окончательные (но это изменение не повлияет на ваш код). Поскольку текущий поток блокируется до тех пор, пока внутренний поток не будет завершен, я не думаю, что вам нужно беспокоиться о синхронизации (но вам может потребоваться заставить переменную нарушать, чтобы вы видели результат).

ИМО, это лучшее решение (другими словами, это то, что я сделал)

John Henckel 02.09.2014 18:24

Если это происходит часто, вам лучше использовать модель подписки / уведомления между вашим процессом и представлением. Ваше представление подписывается на событие, которое должно вызвать это окно сообщения, и получает уведомление при выполнении условий.

Я только что решил эту проблему, и моя первая попытка была аналогичной - массив или список элементов желаемого типа. Но через некоторое время я придумал что-то вроде этого:

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/…

John Henckel 02.09.2014 18:14

Другие вопросы по теме