7

私は Eclipse プラグインを作成していますが、実行中のジョブをしばらく一時停止し、UI スレッドで何かを非同期に実行してから再開する必要がある状況がよくあります。

したがって、私のコードは通常次のようになります。

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!

これを行う 1 つの方法は、Job クラス全体に何らかのフィールドを持たせることです。もう 1 つは、カスタマイズされたクラスを使用することです (このために匿名ではなく、その結果のデータ フィールドを使用するなどです。最善かつ最もエレガントなアプローチは何ですか?

4

3 に答える 3

8

上記のコンテナは「正しい」選択だと思います。タイプセーフのためにジェネリック化することもできます。この種の状況での迅速な選択は、最後の配列イディオムです。秘訣は、Runnable から参照されるすべてのローカル変数が final でなければならないため、変更できないことです。そのため、代わりに単一の要素配列を使用します。この配列は final ですが、配列の要素は変更できます。

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

繰り返しますが、これは匿名クラスがあり、特定の Container クラスを定義せずに結果を貼り付ける場所を与えたい場合の「迅速な」解決策です。

UPDATE これについて少し考えた後、コールバックが同じスレッドにあるリスナーとビジタータイプの使用でこれがうまく機能することに気付きました。ただし、この場合、Runnable は別のスレッドで実行されるため、syncExec が戻った後に実際に結果が表示される保証はありません。正しい解決策は、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());

AtomicReference の値への変更は、あたかも volatile と宣言されているかのように、すべてのスレッドから見えることが保証されています。これについては、こちらで詳しく説明しています。

于 2008-12-10T04:34:58.120 に答える
4

おそらく、呼び出しが戻るまでに非同期Runnableが終了すると想定すべきではありません。asyncExec

その場合、結果をリスナー/コールバック (おそらくコマンド パターン) にプッシュすることを検討していますjava.util.concurrent.Future

于 2008-12-10T14:17:06.150 に答える
0

run()それが同期の場合は、メソッドの外部にある種の値ホルダーを持つことができます。

古典は次のとおりです。

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

コンテナは次のとおりです。

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

もちろん、これは陽気で危険です (さらに危険なのは、新しいリストを作成し、最初の要素を設定して取得することです) が、syncExecメソッドがブロックされるため、悪いことは何も起こりません。

誰かが後で戻ってきてそれを作るときを除いてasyncExec()..

于 2008-12-10T03:55:50.150 に答える