简体   繁体   English

Java Swing EDT和并发

[英]Java Swing EDT & Concurrency

I was just wondering if it is still necessary to ensure synchronicity in an invokeLater() Runnable. 我只是想知道是否仍然需要确保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. 对于相当糟糕的示例感到抱歉,但我们必须假设text被不同的线程修改,无法注入,并且依赖于正确的值。

Is this the proper solution or will I unintentionally create a deadlock problem by sending synchronized code off into an unknown context..? 这是正确的解决方案,还是通过将同步代码发送到未知的上下文中而无意中造成死锁问题?

Thanks. 谢谢。

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. 这将确保如果两个线程尝试同时调用setText那么它们将不会相互破坏。 The first thread in will set the value of text and enqueue a UI update with that value. 第一个线程将设置text的值,并使用该值将UI更新排入队列。 The second thread will also set the value of text and enqueue a second UI update. 第二个线程还将设置text的值并将第二个UI更新排入队列。

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. 最终结果是UI最终将显示最新的文本值,但内部text变量将立即包含最新值。

A couple of notes: 几个笔记:

  1. Using a seperate lock object (ie TEXT_LOCK ) means you are not vulnerable to code somewhere else locking the monitor on the Whatever instance and inadvertently causing a deadlock. 使用单独的锁定对象(即TEXT_LOCK )意味着您不会受到其他地方的代码攻击,无法将监视器锁定在Whatever实例上,并且无意中导致死锁。 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. 可以使整个setText方法同步,但需要注意的是它确实使您可能容易受到上述死锁的影响。
  3. Reading the value of text also needs to be synchronized even though Strings are immutable. 即使Strings是不可变的,也需要同步读取text的值。 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. Java内存模型有一些细微之处,这意味着您总是需要围绕可由多个线程读取/写入的变量进行同步。

Check out Brian Goetz's Java Concurrency in Practice for a great dive into the tricky parts of concurrency (including the memory model weirdness). 查看Brian Goetz的Java Concurrency in Practice ,深入了解并发的棘手部分(包括内存模型的怪异)。

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 现在它是正确的,任务的所有输出都必须包装在InvokeLater()中,另一个来自BackGround任务的更新GUI的例子在这里

private String text;

private void updateText() {

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM