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