代码之家  ›  专栏  ›  技术社区  ›  Matt McHenry

如何检索必须在另一个线程上计算的值

  •  3
  • Matt McHenry  · 技术社区  · 14 年前

    在许多情况下,线程A需要一个必须在线程B上计算的值(最常见的情况是,B==EDT)。请考虑以下示例:

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

    当然,这不会编译,因为匿名内部类不允许写入 host

    7 回复  |  直到 12 年前
        1
  •  2
  •   Community Neeleshkumar S    7 年前

    不:

    使用 Future<T> 可能还有 Callable<T> 还有一个 ExecutorService . 一个 Future 基本上是你想要的一个精确的程序表达: 对未来答案的承诺,以及在答案出现之前阻止的能力 . Future也会自动地为您包装并呈现一个完整的、复杂的farrago,其中包含了潜在的并发噩梦和复杂性,并包含一些明确定义的异常。这是一个 好事

    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 哪些工具 未来 . 请看一下这个而不是复制品 SO question

        2
  •  1
  •   yawn    14 年前
        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));
    
        3
  •  0
  •   Matt McHenry    14 年前

    详细:使用内部类

    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);
    
        4
  •  0
  •   XecP277    14 年前

    我建议创建一个类来处理此问题,示例如下:

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

    if (SwingUtilities.isEventDispatchThread()) {
        host = doHostnameGen.process() ;
    } else {
        SwingUtilities.invokeAndWait(doHostnameGen) ;
        host = doHostnameGen.getValue() ;
    }
    
        5
  •  0
  •   andersoj    14 年前

    请注意:作者不喜欢这个答案,只是对具体问题的“一针见血”的回答。

    如果您只是在等待对上述代码进行最小程度的修改以使其正常工作,那么您所处理的内部类只能引用final问题。划出一个命名的内部类而不是一个匿名类,并在该类中创建一个字符串宿主字段。将该实例传递给 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());
    
        6
  •  -1
  •   Matt McHenry    14 年前

    优雅的?使用原子变量

    final AtomicReference<String> host = new AtomicReference<String>();
    SwingUtilities.invokeAndWait(new Runnable() {
        public void run() {
            host.set(JOptionPane.showInputDialog("Enter host name: "));
        }
    });
    openConnection(host.get());
    
        7
  •  -1
  •   Matt McHenry    14 年前

    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?