在许多情况下,线程A需要一个必须在线程B上计算的值。(最常见的是,B == EDT。)考虑这个例子:
String host;
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
host = JOptionPane.showInputDialog("Enter host name: ");
}
});
openConnection(host);
当然,这不会编译,因为不允许匿名内部类写入host
。让这个最简单,最干净的方法是什么?我已经在下面列出了我所知道的方式。
答案 0 :(得分:2)
没有
使用Future<T>
,可能Callable<T>
和ExecutorService
。 Future
基本上是您想要的精确程序化表达:未来答案的承诺,以及在答案可用之前阻止的能力。 Future还会自动包装并为您呈现潜在的并发噩梦和复杂性的完整复杂的一些例子。这是一个好东西,因为它强迫你处理它们,当你自己的解决方案可能永远不会揭示它们时,除了一些异常的,难以诊断的行为。
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;
}
对于您的具体情况,您可以构建一个实现Future
的{{3}}。请不要复制,请查看此SwingWorker。
答案 1 :(得分: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));
答案 2 :(得分:0)
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);
答案 3 :(得分: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() ;
}
答案 4 :(得分:0)
请注意:作者不喜欢这个答案,只是对具体问题的“嗤之以鼻”答案。
如果您只是等待最低限度地修改上面的代码以便它可以正常工作,那么您将处理内部类只能参与决赛的问题。创建一个命名的内部类而不是匿名的内部类,并在该类中创建一个String主机字段。将该实例传递给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());
答案 5 :(得分:-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());
答案 6 :(得分:-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?