Qual é a melhor maneira de obter um valor de retorno para fora de um asyncExec em Eclipse?

votos
5

Estou escrevendo plugins do Eclipse e, freqüentemente, temos uma situação onde um trabalho em execução precisa parar por um tempo curto, executar algo de forma assíncrona no segmento interface do usuário, e retomar.

Então meu código normalmente é algo como:

Display display = Display.getDefault();
display.syncExec(new Runnable() {
    public void run() {
                // Do some calculation
                // How do I return a value from here?
    }
});
// I want to be able to use the calculation result here!

Uma maneira de fazer isso é ter toda a classe Job tem algum campo. Outra é usar uma classe personalizado (em vez de anonimato por isso e usar seu campo de dados resultante, etc. Qual é a melhor e mais elegante abordagem?

Publicado 10/12/2008 em 02:05
fonte usuário
Em outras línguas...                            


3 respostas

votos
0

Bem, se é sync você pode apenas ter um suporte de valor de algum tipo externa ao run()método.

O clássico é:

final Container container = new Container();
Display display = Display.getDefault();
display.syncExec(new Runnable()
{
  public void run()
  {
    container.setValue("foo");
  }
}
System.out.println(container.getValue());

Onde o container é apenas:

public class Container {
  private Object value;
  public Object getValue() {
    return value;
  }
  public void setValue(Object o) {
    value = o;
  }
}

Este é, naturalmente, hilariante e desonesto (ainda mais desonesto é a criação de uma nova lista e, em seguida, configurar e obter o 1º elemento) mas os syncExecblocos método de modo nada de ruim vem dele.

Exceto quando alguém vem voltar mais tarde e torna mais asyncExec()..

Respondeu 10/12/2008 em 04:55
fonte usuário

votos
7

Eu acho que o Container acima é a escolha "certa". Poderia também ser genericized para a segurança tipo. A escolha rápida neste tipo de situação é a expressão final de array. O truque é que um qualquer variáveis ​​locais referenciados do Runnable deve ser final, e, portanto, não pode ser modificado. Então, em vez disso, você usa um único elemento de matriz, onde a matriz é final, mas o elemento da matriz pode ser modificada:

final Object[] result = new Object[1];
Display display = Display.getDefault();
display.syncExec(new Runnable()
{
  public void run()
  {
    result[0] = "foo";
  }
}
System.out.println(result[0]);

Mais uma vez, esta é a solução "rápida" para aqueles casos em que você tem uma classe anônima e você quer dar-lhe um lugar para ficar resultado sem definir uma classe de contêiner específico.

ATUALIZAÇÃO Depois eu pensei sobre isso um pouco, percebi isso funciona bem para o uso do ouvinte e visitante tipo onde o retorno é no mesmo segmento. Neste caso, no entanto, o Runnable executa em um segmento diferente para que você não está garantido para realmente ver o resultado depois retorna syncExec. A solução correcta é a utilização de um AtomicReference:

final AtomicReference<Object> result = new AtomicReference<Object>();
Display display = Display.getDefault();
display.syncExec(new Runnable()
{
  public void run()
  {
    result.set("foo");
  }
}
System.out.println(result.get());

Alterações no valor de AtomicReference são garantidos para ser visível por todos os tópicos, como se fosse declarado volátil. Isto é descrito em detalhes aqui .

Respondeu 10/12/2008 em 05:34
fonte usuário

votos
4

Você provavelmente não deve ser assumindo que o assíncrono Runnableterá terminado no momento em que os asyncExecchamada retorna.

Nesse caso, você está olhando para empurrar o resultado fora para ouvintes / retornos de chamada (padrão possivelmente comando), ou se você quer ter o resultado disponível a um mais tarde no mesmo método, usando algo parecido com um java.util.concurrent.Future.

Respondeu 10/12/2008 em 15:17
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more