2008-09-16 2 views
2

В моем приложении Java SWT я часто хочу возвращать информацию из вызова Display.syncExec(). Лучший способ я нашел до сих пор сделать это:Каков наилучший способ возврата переменных из 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 потокобезопасно, но есть лучший контейнер, я должен использовать, или простой способ в целом?

ответ

5

ArrayList is not thread-safe. Вы можете получить поточный сейф 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()) { /* ... */ } 
1

ArrayList is не поточно-безопасный. Из соответствующих Javadoc:

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

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

+1

Вы правы, но на самом деле это не так важно, потому что блоки .syncExec. – SCdF 2008-09-16 20:23:01

1

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

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

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

+0

IMO это лучшее решение (другими словами, это то, что я сделал) – 2014-09-02 14:24:12

1

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

3

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

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 

Это намного более аккуратный и удаляет избыточные переменные.

BTW. Сначала я попытался использовать UIThreadRunnable, но мне не нужна зависимость SWTBot, поэтому я отказался от этого решения. После того, как я сделал свое собственное решение, я узнал, что там они используют подобную работу.

+0

Вы должны использовать Callable. Это похоже на Runnable, но позволяет вернуться. http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Callable.html – 2014-09-02 14:14:08

Смежные вопросы