我怎样才能实现一个 returns 结果到事件调度线程的方法?

How can I implement a method that returns a result to Event Dispatch Thread?

我有以下方法:

public Object someMethod(Object param) {
    return performLongCalculations();
}

一些耗时的计算我放在了单独的方法中:

private Object performLongCalculations() {
    ...
}

问题是它 return 是一些计算结果。这些计算在 EDT 中执行并导致冻结 UI.

我尝试通过以下方式解决:

public Object someMethod(final Object param) {
    Object resultObject = new Object();
    ExecutorService executorService = Executors.newFixedThreadPool(1);
    Future<Object> future = executorService.submit(new Callable<Object>() {
        @Override
        public Object call() {
            return performLongCalculations(param);
        }
    });
    
    executorService.shutdown();

    try {
        resultObject = future.get();
    } catch (InterruptedException | ExecutionException  e) {
      // ...
    }
    return resultObject;
}

但是线程在调用 future.get(); 时被阻塞,直到计算完成。我认为它也在 EDT.

中运行

接下来我尝试使用 SwingWorker:

public Object someMethod(final Object param) {
    SwingWorker<Object, Void> worker = new SwingWorker<Object, Void>() {
        @Override
        protected Object doInBackground() {
            return performLongCalculations(param);
        }

        @Override
        protected void done() {
            try {
                get();
            } catch (InterruptedException e) {

            }
            catch (ExecutionException e) {

            }
        }
    };
    worker.execute();
    // what should I return here?
}

这里我需要 return 结果,但它在与 EDT 并行运行的线程结束前 returns。

你的问题本质上是:

How can I return a value directly into my Swing GUI from a method where the solution is obtained from long-running code called within a background thread?

简而言之,答案是:你不知道。

尝试以任何方式、形式或方式执行此操作将意味着强制后台线程阻塞 GUI 事件线程,直到后台线程完成其任务,并且如果该任务需要任何可观的时间,那么这将始终导致 GUI 冻结。相反,您必须在后台线程完成时提取信息,而不是从方法本身获取结果。这通常使用某种回调机制来完成。

例如,在这段代码中:

public void someMethod(final Object param) {
    SwingWorker<Object, Void> worker = new SwingWorker<Object, Void>() {
        @Override
        protected Object doInBackground() {
            return performLongCalculations(param);
        }

        @Override
        protected void done() {
            try {
                Object something = get();
                
                // (A)
                
            } catch (InterruptedException e) {
                // do handle these exceptions!
            }
            catch (ExecutionException e) {
                // do handle these exceptions!
            }
        }
    };
    worker.execute();
    
    // (B)
}

您将在位置 (A) 处将结果作为 return 方法的值提供给 GUI,位置 (B)

或者,您可以将 PropertyChangeListener 附加到 SwingWorker,侦听 Worker 的状态 属性 何时更改为 SwingWorker.StateValue.DONE,然后在 worker 上调用 .get() 并推送值 returned 到 GUI 上。这是我的首选方式,因为它通常允许较低的代码耦合。