简体   繁体   English

如何实现将结果返回到事件调度线程的方法?

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

I have the following method:我有以下方法:

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

Some time consuming calculations I placed in a separate method:我将一些耗时的计算放在一个单独的方法中:

private Object performLongCalculations() {
    ...
}

The problem is that it returns some calculation result.问题是它返回了一些计算结果。 These calculations are performed in the EDT and lead to freezing the UI .这些计算在EDT中执行并导致冻结UI

I tried to solve it with the following way:我尝试通过以下方式解决它:

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;
}

But the thread is blocked on the call to future.get();但是线程在调用future.get(); until the calculations are completed.直到计算完成。 And I think it also runs in EDT .而且我认为它也在EDT中运行。

Next I tried to use SwingWorker :接下来我尝试使用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?
}

Here I need to return the result, but it returns before the end of the thread that runs in parallel with EDT.这里我需要返回结果,但它在与 EDT 并行运行的线程结束之前返回。

Your question essentially is:你的问题本质上是:

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?如何通过从后台线程中调用的长时间运行代码获得解决方案的方法将值直接返回到我的 Swing GUI 中?

And the answer, succinctly, is: you don't.简而言之,答案是:你不知道。

Trying to do this in any way, shape or fashion would mean forcing the background thread to block the GUI event thread until the background thread has completed its task, and if the task takes any appreciable time, then this will always cause the GUI to freeze.尝试以任何方式、形状或方式执行此操作将意味着强制后台线程阻塞 GUI 事件线程,直到后台线程完成其任务,并且如果该任务花费任何可观的时间,那么这将始终导致 GUI 冻结. Instead, you must extract the information when the background thread has completed, and not get the result from the method itself.相反,您必须在后台线程完成时提取信息,而不是从方法本身获取结果。 This is usually done using a call-back mechanism of some sort.这通常使用某种回调机制来完成。

For example, in this code:例如,在这段代码中:

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)
}

You would give the result to the GUI at location (A) not as a return value from the method, location (B)您会将结果提供给位于位置(A)的 GUI,而不是作为方法位置(B)的返回值

Alternatively, you could attach a PropertyChangeListener to the SwingWorker, listen for when Worker's state property changes to SwingWorker.StateValue.DONE , and then call .get() on the worker and push the value returned onto the GUI.或者,您可以将 PropertyChangeListener 附加到 SwingWorker,监听 Worker 的 state 属性何时更改为SwingWorker.StateValue.DONE ,然后在 Worker 上调用.get()并将返回的值推送到 GUI。 This is my preferred way of doing this because it usually allows for lower code coupling.这是我的首选方式,因为它通常允许较低的代码耦合。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM