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

StackOverflow https://stackoverflow.com/questions/76300

  •  09-06-2019
  •  | 
  •  

Вопрос

В моем Java-приложении SWT я часто хочу возвращать информацию изнутри вызова 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, поэтому я отказался от этого решения.После того, как я создал свое собственное решение, я узнал, что они используют аналогичную работу и там.

ArrayList - это нет потокобезопасен.Из соответствующих Javadoc:

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

Если вам нужна потокобезопасная реализация List, в JDK есть (как минимум) две из них:CopyOnWriteArrayList и вектор.

Вы могли бы использовать массив Integer [1], чтобы сделать его более кратким, но я не думаю, что он может напрямую обновлять неокончательную переменную изнутри анонимного внутреннего класса.

final Integer[] result = new Integer[1];

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top