3

スレッドAがスレッドBで計算する必要のある値を必要とする場合が多くあります(最も一般的には、B == EDTです)。次の例を検討してください。

String host;
SwingUtilities.invokeAndWait(new Runnable() {
    public void run() {
        host = JOptionPane.showInputDialog("Enter host name: ");
    }
});
openConnection(host);

もちろん、匿名の内部クラスはに書き込むことが許可されていないため、これはコンパイルされませんhost。これを機能させるための最も簡単でクリーンな方法は何ですか?私が知っている方法を以下に含めました。

4

7 に答える 7

2

いいえ:

Future<T>、場合によってはとを使用します。Aは基本的に、あなたが望むものの正確なプログラム表現です:将来の答えの約束、そして答えが利用可能になるまでブロックする能力。Futureはまた、潜在的な同時実行の悪夢と複雑さの複雑なファラゴ全体を、いくつかの明確に定義された例外に自動的にラップして提示します。これは良いことです。なぜなら、自分で作成したソリューションでは、異常で診断が難しい動作を除いて、それらが明らかになることはない可能性が高い場合に、それらに対処する必要があるからです。Callable<T>ExecutorServiceFuture

public void askForAnAnswer() throws TimeoutException, InterruptedException, ExecutionException
{
  Future<String> theAnswerF = getMeAnAnswer();
  String theAnswer = theAnswerF.get();

}

public Future<String> getMeAnAnswer()
{
  Future<String> promise = null;
  // spin off thread/executor, whatever.
  SwingUtilities.invokeAndWait(new Runnable() {
  public void run() {
    host = JOptionPane.showInputDialog("Enter host name: ");
  }
 });
 // ... to wrap a Future around this.

  return promise;
}

特定のケースでは、おそらくを実装するSwingWorker上に構築できますFuture。複製するのではなく、このSOの質問を見てください。

于 2010-10-20T20:45:49.520 に答える
1
    final SynchronousQueue<String> host = new SynchronousQueue<String>();

    SwingUtilities.invokeAndWait(new Runnable() {

        public void run() {
            host.add(JOptionPane.showInputDialog("Enter host name: "));
        }

    });

    openConnection(host.poll(1, TimeUnit.SECONDS));
于 2010-10-20T21:12:03.317 に答える
0

Verbose:内部クラスを使用する

class HostGetter implements Runnable{
    volatile String host;
    public void run() {
        host = JOptionPane.showInputDialog("Enter host name: ");
    }
}
HostGetter hg = new HostGetter();
SwingUtilities.invokeAndWait(hg);
openConnection(hg.host);
于 2010-10-20T20:18:56.637 に答える
0

これを処理するクラスを作成することをお勧めします。以下のサンプルをご覧ください。

class SyncUserData implements Runnable {
    private String value ;

    public void run() {
        value = JOptionPane.showInputDialog("Enter host name: ") ;
    }

    public String getValue() {
        return value ;
    }
}
// Using an instance of the class launch the popup and get the data.
String host;
SyncUserData syncData = new SyncUserData() ;
SwingUtilities.invokeAndWait(syncData);
host = syncData.getValue() ;

クラスを抽象化し、ジェネリックスを使用して任意のタイプの値を返すことができるようにすることで、このアプローチを拡張します。

abstract class SyncUserDataGeneric<Type> implements Runnable {
    private Type value ;
    public void run() {
        value = process();
    }
    public Type getValue() {
        return value ;
    }

    public abstract Type process() ;
}

String host;
SyncUserDataGeneric<String> doHostnameGen ;

doHostnameGen = new SyncUserDataGeneric<String>() {
    public String process() {
        return JOptionPane.showInputDialog("Enter host name: ");
    }
};

host = doHostnameGen.getValue() ;

編集:EventDispatchThreadから実行されているかどうかを確認します。

if (SwingUtilities.isEventDispatchThread()) {
    host = doHostnameGen.process() ;
} else {
    SwingUtilities.invokeAndWait(doHostnameGen) ;
    host = doHostnameGen.getValue() ;
}
于 2010-10-20T22:53:36.880 に答える
0

注意:作者はこの答えが好きではありません。それは特定の質問に対する「鼻の先」の答えにすぎません。

上記のコードを最小限に変更して機能するようにするための待機のみを探している場合は、inner-class-can-only-refer-to-finalsの問題に対処しています。匿名クラスではなく名前付き内部クラスを作成し、そのクラスに文字列ホストフィールドを作成します。そのインスタンスをに渡しますinvokeAndWait()。しかし、これは私の謙虚な意見ではまだ厄介であり、私Future<>が上で引用したアプローチよりもはるかに劣っています。

class FooWidget implements Runnable() {
  AtomicReference<String> host = new AtomicReference<String>(null);
  @Override
  public void run() {
    host.set(JOptionPane.showInputDialog("Enter host name: "));
  }
}

...

FooWidget foo = new FooWidget();
SwingUtilities.invokeAndWait(foo);
if (foo.host.get() == null) { throw new SomethingWentWrongException(); }
openConnection(foo.host.get());
于 2010-10-20T23:00:03.760 に答える
-1

ハック:配列を使用する

final String[] host = new String[1];
SwingUtilities.invokeAndWait(new Runnable() {
    public void run() {
        host[0] = JOptionPane.showInputDialog("Enter host name: ");
    }
});
openConnection(host[0]); //maybe not guaranteed to be visible by the memory model?
于 2010-10-20T20:19:38.053 に答える
-1

エレガント?アトミック変数を使用する

final AtomicReference<String> host = new AtomicReference<String>();
SwingUtilities.invokeAndWait(new Runnable() {
    public void run() {
        host.set(JOptionPane.showInputDialog("Enter host name: "));
    }
});
openConnection(host.get());
于 2010-10-20T20:18:20.460 に答える