从后台线程调用主线程上的函数

时间:2011-08-10 20:28:06

标签: java swing concurrency swingworker runnable

更新

我已经更新了这个问题,使用建议的SwingWorker类包含Java实现的源代码,以完成与Objective-C示例相同的结果。希望这对未来的冒险家有所帮助。

Document myDoc = ...;
Model myModel = ...;

SwingWorker analyzeDocument = new SwingWorker<Dictionary, Void>() {
    @Override
    public Dictionary doInBackground() {
        return myDoc.analyze();
    }

    @Override
    public void done() {
        try {
            stats = get();
            myModel.setDict(stats);
            myModel.setNeedsDisplay(true);
        } catch(InterruptedException ex) {
            // log
        } catch(ExecutionException ex) {
            // log
        }
    }
};

analyzeDocument.execute();

原帖

在并发编程方面,我缺乏经验,我希望有人能够向我解释如何实现这一目标。

在Objective-C(使用GCD)中,您可以执行以下操作:

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
     NSDictionary *stats = [myDoc analyze];
     dispatch_async(dispatch_get_main_queue(), ^{
       [myModel setDict:stats];
       [myStatsView setNeedsDisplay:YES];
       [stats release];
     });
 });

此代码将在后台线程中执行[myDoc analyze],跟随回调函数更新将在主线程中执行的UI。换句话说,后台线程向主线程发送一个中断,将匿名函数添加到要调用的主线程队列中。显然我不能在Java中使用匿名函数,但这不是重点。

我有兴趣在Java中做这件事。我有一个Runnable对象在文件系统中执行一堆东西。完成后,我想相应地更新UI。

为了在执行此操作时不挂起主线程(即:backgroundThread.join();),我设置了后台线程来执行回调函数来更新UI。但这不是一个好主意,我不希望非GUI线程更新GUI。

我想到的其他一些想法是投票,但这似乎就是抛出一些循环。根据同样的判断,使用期货似乎也不是答案。这一切似乎都打败了异步行动的目的。

我唯一能想到的是从后台线程中使用SwingUtilities.invokeLater并使用它来更新GUI。但我很好奇这将执行哪个线程。

也许我的看法只是扭曲了,但这似乎是一个非常重要的部分。我只是想以错误的方式解决这个问题吗?

2 个答案:

答案 0 :(得分:6)

您是否考虑过创建和使用SwingWorker对象?这允许您轻松地在事件线程的线程背景中运行代码,并且实际上也是Future对象,因此它可以返回结果,并且您可以在其done()方法中使用此结果来更新事件线程上的GUI。您甚至可以通过publish / process方法对在运行过程中对Swing事件线程进行调用。

有关详情,请查看:Concurrency in Swing

答案 1 :(得分:2)

如果您使用Callable<V>代替Runnable,则可以返回一个值。

另外,请查看课程Executors