在编写计算量很大的应用程序时,我尝试使用SwingWorker类将负载分散到多个CPU核心。然而,这个类的行为被证明有点奇怪:似乎只使用了一个核心。
在网上搜索时,我在网上找到了一个很好的答案(参见Swingworker instances not running concurrently,由用户268396回答),除了问题的原因外,还提到了一个可能的解决方案:
你可以做些什么来解决这个问题,使用ExecutorService并发布 FutureTasks就可以了。这些将提供99%的SwingWorker API (SwingWorker是FutureTask派生物),您只需设置即可 你的执行官。
作为一名Java初学者,我并不完全确定如何正确地做到这一点。不仅我需要将一些初始数据传递给FutureTask对象,我还需要像使用SwingWorker一样得到结果。因此,非常感谢任何示例代码。
NVX
====================编辑====================
在实施FutureTask that implements Callable中提到的简单而优雅的解决方案之后,出现了另一个问题。如果我使用ExecutorService
创建单个线程,如何在线程完成运行后执行特定代码?
我试图覆盖FutureTask
对象的done()(参见下面的代码),但我想应该在应用程序中完成“显示结果”位(或任何GUI相关的东西)事件派遣线程(EDT)。因此:如何将runnable提交给EDT?
package multicoretest;
import java.util.concurrent.*;
public class MultiCoreTest {
static int coresToBeUsed = 4;
static Future[] futures = new Future[coresToBeUsed];
public static void main(String[] args) {
ExecutorService execSvc = Executors.newFixedThreadPool(coresToBeUsed);
for (int i = 0; i < coresToBeUsed; i++) {
futures[i] = execSvc.submit(new Worker(i));
}
execSvc.shutdown();
// I do not want to block the thread (so that users can
// e.g. terminate the computation via GUI)
//execSvc.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
}
static class Worker implements Callable<String> {
private final FutureTask<String> futureTask;
private final int workerIdx;
public Worker(int idx) {
workerIdx = idx;
futureTask = new FutureTask<String>(this) {
@Override
protected void done() {
Runnable r = new Runnable() {
@Override
public void run() {
showResults(workerIdx);
}
};
r.run(); // Does not work => how do I submit the runnable
// to the application's event dispatch thread?
}
};
}
@Override
public String call() throws Exception {
String s = "";
for (int i = 0; i < 2e4; i++) {
s += String.valueOf(i) + " ";
}
return s;
}
final String get() throws InterruptedException, ExecutionException {
return futureTask.get();
}
void showResults(int idx) {
try {
System.out.println("Worker " + idx + ":" +
(String)futures[idx].get());
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
}
答案 0 :(得分:2)
我尝试使用SwingWorker类将负载分散到 多个CPU核心。然而,这个类的行为被证明是 有点奇怪:似乎只使用了一个核心。
不知道没有发布SSCCE,简短,可运行,可编辑,
SwingWorker
被指定为Swing GUI创建Workers Thread
,more in this thread
答案 1 :(得分:2)
有几点:
run()
/ call()
方法的最后一步,请使用SwingUtilities.invokeLater()
代码来更新ui。注意,您仍然可以使用SwingWorker
,而不是调用execute()
,而是将SwingWorker提交给您的执行者。
如果你需要在更新gui之前完成所有线程的同时处理所有结果,那么我建议:
SwingUtilities.invokeLater()