Jaki jest najlepszy sposób, aby uzyskać wartości zwracanej się o asyncExec w Eclipse?

głosy
5

Piszę wtyczek Eclipse, a często do czynienia z sytuacją, gdzie potrzebuje uruchomiony Praca aby wstrzymać na chwilę uruchomić coś asynchronicznie w wątku UI i wznowić.

Więc mój kod zazwyczaj wygląda mniej więcej tak:

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!

Jednym ze sposobów, aby to zrobić jest, aby cała klasa Praca jakieś pole. Innym jest używać własnego klasę (zamiast anonimowy do tego i użyć jej wynikającej pole danych, itd. Jaki jest najlepszy i najbardziej elegancki podejście?

Utwórz 10/12/2008 o 02:05
źródło użytkownik
W innych językach...                            


3 odpowiedzi

głosy
7

Myślę, że Container powyżej jest „prawo” wyborem. To może być również genericized dla bezpieczeństwa typu. Szybki wybór w tego rodzaju sytuacji jest ostateczna tablica idiom. Sztuką jest, że wszelkie zmienne lokalne przywoływane z przypisanymi musi być ostateczna, a zatem nie mogą być modyfikowane. Więc zamiast tego użyć pojedynczego elementu tablicy, na której tablica jest ostateczna, ale element tablicy może być modyfikowany:

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

Ponownie, jest to „szybkie” rozwiązanie dla tych przypadkach, gdzie trzeba anonimową klasę i chcesz dać mu się trzymać wynik bez określenia konkretnej klasy kontenera.

UPDATE Po myślałem o tym trochę, zdałem sobie sprawę, to działa dobrze do użytku słuchacz i odwiedzających typu gdzie zwrotna jest w tym samym wątku. W tym przypadku jednak, Runnable wykonywany w innym wątku, więc nie masz gwarantowane, aby rzeczywiście zobaczyć wynik po syncExec zwrotów. Poprawnym rozwiązaniem jest użycie 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());

Zmiany wartości AtomicReference są gwarantowane być widoczne przez wszystkich wątków, tak jakby zostały zadeklarowane zmienne. Jest to opisane szczegółowo tutaj .

Odpowiedział 10/12/2008 o 05:34
źródło użytkownik

głosy
4

Prawdopodobnie nie powinno być przy założeniu, że asynchroniczny Runnablebędą zakończeniu przez czas asyncExecpowraca połączeń.

W takim przypadku, patrzysz na wynik pchanie się do słuchaczy / wywołania zwrotne (ewentualnie wzór polecenia), lub jeśli nie chcemy mieć wynik dostępne później w ten sam sposób, używając coś jak java.util.concurrent.Future.

Odpowiedział 10/12/2008 o 15:17
źródło użytkownik

głosy
0

Dobrze, jeśli jest to synchronizacja może po prostu masz uchwyt wartość jakiegoś zewnętrznego do run()metody.

Klasyczny jest:

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

Gdzie zbiornik jest tylko:

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

Jest to oczywiście zabawne i podejrzanie (nawet bardziej ryzykowna jest stworzenie nowej listy, a następnie ustawienie i uzyskanie 1-ej), ale syncExecblokuje metoda więc nic złego pochodzi od niego.

Wyjątkiem sytuacji, gdy ktoś przychodzi później i czyni go asyncExec()..

Odpowiedział 10/12/2008 o 04:55
źródło użytkownik

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