如何正确扩展FutureTask



在编写计算量很大的应用程序时,我尝试使用SwingWorker类将负载分散到多个CPU内核。然而,这个类的行为被证明有些奇怪:似乎只使用了一个核心。

在互联网上搜索时,我在这个网站上找到了一个很好的答案(见Swingworker实例不并发运行,答案由user268396),除了问题的原因之外,还提到了一个可能的解决方案:

你可以使用ExecutorService和post来解决这个问题FutureTasks在上面。这些将提供99%的SwingWorker API(SwingWorker是FutureTask的衍生物),你所要做的就是设置

作为一个Java初学者,我不完全确定如何正确地做到这一点。我不仅需要将一些初始数据传递给FutureTask对象,还需要像使用SwingWorker一样获得返回结果。因此,任何示例代码都将非常感谢。

nvx

==================== 编辑 ====================

在实现了FutureTask中提到的实现Callable的简单而优雅的解决方案之后,另一个问题出现了。如果我使用ExecutorService来创建单独的线程,我如何在线程完成运行后执行特定的代码?

我试图覆盖FutureTask对象的done()(见下面的代码),但我猜"显示结果"位(或任何GUI相关的东西)应该在应用程序的事件调度线程(EDT)中完成。因此:我如何向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());
            }
        }
    }
}

几点说明:

  • 你很少需要直接使用FutureTask,只需要实现Callable或Runnable并将实例提交给Executor
  • 为了在完成后更新gui,作为run()/call()方法的最后一步,使用SwingUtilities.invokeLater()与代码一起更新ui。

注意,你仍然可以使用SwingWorker,只是,不是调用execute(),而是将SwingWorker提交给你的Executor。

如果您需要在更新gui之前处理所有线程完成时一起处理所有结果,那么我建议:

  • 让每个worker将其结果存储到线程安全的共享列表中
  • 最后一个将结果添加到列表的 worker应该然后执行后处理工作
  • 完成后处理工作的worker应该调用SwingUtilities.invokeLater()并获得最终结果

我试图利用SwingWorker类来分散负载多个CPU内核。然而,这个班级的行为被证明是有点奇怪:似乎只使用了一个核心。

  • 不知道不张贴SSCCE,短,可运行,可编译,

  • SSCCE可基于

  • SwingWorker被指定为Swing GUI创建Workers Thread,在这个线程中

相关内容

  • 没有找到相关文章

最新更新