Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何实现将结果返回到事件分派线程的方法?_Java_Multithreading_Swing_Concurrency_Swingworker - Fatal编程技术网

Java 如何实现将结果返回到事件分派线程的方法?

Java 如何实现将结果返回到事件分派线程的方法?,java,multithreading,swing,concurrency,swingworker,Java,Multithreading,Swing,Concurrency,Swingworker,我有以下方法: public Object someMethod(Object param) { return performLongCalculations(); } 我将一些耗时的计算放在单独的方法中: private Object performLongCalculations() { ... } 问题是它返回了一些计算结果。这些计算在EDT中执行,并导致冻结UI 我试着用以下方法解决它: public Object someMethod(final Object pa

我有以下方法:

public Object someMethod(Object param) {
    return performLongCalculations();
}
我将一些耗时的计算放在单独的方法中:

private Object performLongCalculations() {
    ...
}
问题是它返回了一些计算结果。这些计算在
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;
}

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

您的问题本质上是:

如果解决方案是从后台线程中调用的长时间运行的代码中获得的,那么如何将值直接从该方法返回到Swing GUI中

简而言之,答案是:你没有

尝试以任何方式、形状或方式执行此操作都意味着强制后台线程阻止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)
}
public void somethod(最终对象参数){
SwingWorker worker=新SwingWorker(){
@凌驾
受保护对象doInBackground(){
返回性能计算(参数);
}
@凌驾
受保护的void done(){
试一试{
objectsomething=get();
//(A)
}捕捉(中断异常e){
//一定要处理这些异常!
}
捕获(执行例外){
//一定要处理这些异常!
}
}
};
worker.execute();
//(B)
}
您可以在位置
(A)
处将结果提供给GUI,而不是作为方法的返回值,位置
(B)


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

这里的关键技术是:“异步编程”。EDT只会启动计算,然后重新开始工作。当计算线程完成时,它向EDT发送信号(为了防止内存老化,应该通过调用
SwingUtilities.invokeLater()
)@MarkJeronimus:correction:the
.invokeLater()
位在这里不应该使用,如果结果是在工作线程的
done()中返回的话
方法或通过
PropertyChangeListener
,这两种方法都是我上面建议的,因为以这种方式调用的代码已经在EDT上调用了。如果您试图从其他类型的后台线程中调用Swing GUI,则只需使用
SwingUtilities.invokeLater()
。@MarkJeronimus:SwingWorker有一个内部PropertyChangeSupport,它实际上是SwingPropertyChangeSupport子类,因此它的回调方法保证在EDT上被调用。同样,保证在EDT上调用worker的
done()
方法。
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)
}