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

发布于 2024-11-29 02:37:59 字数 1668 浏览 1 评论 0原文

更新

我已经更新了这个问题,以包含 Java 实现的源代码,使用建议的 SwingWorker 类,以实现与 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];
     });
 });

此代码将在后台线程中执行 [myDocanalyze],遵循回调函数来更新将执行的 UI在主线程中。换句话说,后台线程向主线程发送中断,将匿名函数添加到主线程的调用队列中。显然我无法在 Java 中使用匿名函数,但这不是重点。

我有兴趣在 Java 中为此做一些事情。我有一个 Runnable 对象,它在文件系统中执行一系列操作。完成后,我想相应地更新用户界面。

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

我想到的其他一些想法是轮询,但这似乎将循环扔出了窗外。根据同样的判断,使用 Futures 似乎也不是答案。这一切似乎都违背了异步操作的目的。

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

也许我的看法是扭曲的,但这似乎是一个相当大的部分可以忽略。我只是想以错误的方式解决这个问题吗?

Update

I've updated this question to include source code of a Java implementation, using the suggested SwingWorker class, to accomplish the same result as the Objective-C example. Hopefully this will be of aid to future adventurers.

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();

Original Post

I'm inexperienced when it comes to concurrent programming and I was hoping someone may be able to explain to me how I can achieve this.

In Objective-C (with GCD), you're able to do something like this:

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

This code will execute [myDoc analyze] in the background thread, following a callback function to update the UI which will executed in the main thread. In other words, the background thread sends an interrupt to the main thread, adding the anonymous function to the main thread's queue to be invoked. Obviously I won't be able to use anonymous functions in Java, but that's beside the point.

I am interested in doing something to this effect in Java. I have a Runnable object which does a bunch of stuff in the file system. When it finishes, I want to update the UI accordingly.

In an effort to not hang the main thread while doing this (ie: backgroundThread.join();), I've set the background thread to execute a callback function to update the UI. But this isn't a good idea, I don't want a non-GUI thread updating the GUI.

Some other ideas I've thought of is polling, but that seems like throwing cycles out the window. By the same judgement, using Futures doesn't seem to be the answer either. This all seems to defeat the purpose of an asynchronous action.

The only other thing I can think of is using SwingUtilities.invokeLater from the background thread and using it to update the GUI. But I'm curious in which thread this would be executed.

Maybe my perception is just warped, but this seems like it would be a pretty big part to leave out. Am I just trying to go about this the wrong way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

俏︾媚 2024-12-06 02:37:59

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

有关详细信息,请查看:Swing 中的并发

Have you looked into creating and using a SwingWorker object? This allows you to easily run code in a thread background to the event thread, and in fact is a Future object as well and so it can return a result, and you can use this result in its done() method to update the GUI on the event thread. You can even do calls on the Swing event thread in the middle of its run via the publish/process method pair.

For more on this, please check out: Concurrency in Swing

故事未完 2024-12-06 02:37:59

如果您使用 Callable 而不是 Runnable,则可以返回一个值。

另外,看看Executors类。

If you use Callable<V> instead of Runnable, you can return a value.

Also, take a look at class Executors.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文