Java Swing EDT 和 Java Swing并发性

发布于 2024-11-26 15:47:55 字数 539 浏览 2 评论 0原文

我只是想知道是否仍然有必要确保 invokeLater() Runnable 的同步性。

我遇到了死锁,需要在保持并发性的同时克服它。

这是一个好的代码示例吗?:

private String text;

private void updateText()
{
    SwingUtilities.invokeLater(new Runnable()
    {
        public void run()
        {
            synchronized(FrameImpl.this)
            {
                someLabel.setText(text);
            }
        }
    });
}

对于这个相当糟糕的示例感到抱歉,但我们必须假设 text 正在被不同的线程修改,无法注入,并且依赖于正确的值。

这是正确的解决方案吗?还是我会通过将同步代码发送到未知的上下文中而无意中造成死锁问题?

谢谢。

I was just wondering if it is still necessary to ensure synchronicity in an invokeLater() Runnable.

I am encountering deadlock and need to overcome it while maintaining concurrency.

Would this be an example of good code?:

private String text;

private void updateText()
{
    SwingUtilities.invokeLater(new Runnable()
    {
        public void run()
        {
            synchronized(FrameImpl.this)
            {
                someLabel.setText(text);
            }
        }
    });
}

Sorry for the rather bad example, but we must assume that text is being modified by different threads, cannot be injected, and is reliant on a correct value.

Is this the proper solution or will I unintentionally create a deadlock problem by sending synchronized code off into an unknown context..?

Thanks.

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

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

发布评论

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

评论(2

最美的太阳 2024-12-03 15:47:55

更好的解决方案是这样的:

public class Whatever {
    private String text;
    private final Object TEXT_LOCK = new Object();

    public void setText(final String newText) {
        synchronized (TEXT_LOCK) {
            text = newText;
        }
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                someLabel.setText(newText);
            }
        });
    }

    public String getText() {
        synchronized (TEXT_LOCK) {
            return text;
        }
    }
}

这将确保如果两个线程尝试同时调用 setText,那么它们不会互相干扰。第一个线程将设置 text 的值,并使用该值将 UI 更新排入队列。第二个线程还将设置 text 的值并将第二个 UI 更新排入队列。

最终结果是 UI 最终将显示最新的文本值,但内部 text 变量将立即包含最新的值。

一些注意事项:

  1. 使用单独的锁定对象(即 TEXT_LOCK)意味着您不会受到其他地方的代码的影响,将监视器锁定在 Whatever 实例上并无意中导致死锁。最好始终严格控制您的锁定对象。最好还是最小化同步块的大小。
  2. 可以使整个setText方法同步,但需要注意的是,它确实使您可能容易陷入上述死锁。
  3. 即使Strings 是不可变的,读取text 的值也需要同步。 Java 内存模型有一些微妙之处,这意味着您总是需要同步可由多个线程读取/写入的变量。

查看 Brian Goetz 的 Java 并发实践,深入了解其中的棘手部分并发性(包括奇怪的内存模型)。

A better solution would be something like this:

public class Whatever {
    private String text;
    private final Object TEXT_LOCK = new Object();

    public void setText(final String newText) {
        synchronized (TEXT_LOCK) {
            text = newText;
        }
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                someLabel.setText(newText);
            }
        });
    }

    public String getText() {
        synchronized (TEXT_LOCK) {
            return text;
        }
    }
}

This will ensure that if two threads try to call setText concurrently then they will not clobber each other. The first thread in will set the value of text and enqueue a UI update with that value. The second thread will also set the value of text and enqueue a second UI update.

The end result is that the UI will eventually show the most recent text value, but the internal text variable will immediately contain the most recent value.

A couple of notes:

  1. Using a seperate lock object (i.e. TEXT_LOCK) means you are not vulnerable to code somewhere else locking the monitor on the Whatever instance and inadvertently causing a deadlock. Best to always keep tight control of your lock objects. It's also best to minimize the size of your synchronized blocks.
  2. You could make the whole setText method synchronized, subject to the caveat that it does make you potentially vulnerable to deadlock as above.
  3. Reading the value of text also needs to be synchronized even though Strings are immutable. There are subtleties to the Java memory model that mean you always need to synchronize around variables that can be read/written by multiple threads.

Check out Brian Goetz's Java Concurrency in Practice for a great dive into the tricky parts of concurrency (including the memory model weirdness).

日暮斜阳 2024-12-03 15:47:55

现在这是正确的,任务的所有输出都必须包装到 InvokeLater() 中,从 BackGround 任务更新 GUI 的另一个示例是 此处

private String text;

private void updateText() {

    synchronized (FrameImpl.this) {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                someLabel.setText(text);
            }
        });
    }
}

now it would be correct, all output from task must be wrapped ito InvokeLater(), another example for update GUI from BackGround task(s) is here

private String text;

private void updateText() {

    synchronized (FrameImpl.this) {
        SwingUtilities.invokeLater(new Runnable() {

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