如果Swing模型的getter不是线程安全的,你如何处理它们? [英] If Swing models' getters aren't thread-safe, how do you handle them?

查看:144
本文介绍了如果Swing模型的getter不是线程安全的,你如何处理它们?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

众所周知,更新Swing GUI必须在EDT中完成。较少的广告是来自GUI的读取内容必须/也应该在EDT中完成。例如,让我们来看看 ButtonModel的isSelected() 方法,告诉(例如)ToggleButton的状态(向下或向上)。

It is well known that updating a Swing GUI must be done exclusively in the EDT. Less is advertised that reading stuff from the GUI must/should also be done in the EDT. For instance, let's take ButtonModel's isSelected() method, which tells (for instance) ToggleButton's state ("down" or "up").

在我看过的每个例子中, isSelected()可以从主线程或任何线程中自由查询。但是当我查看DefaultButtonModel的实现时,它没有同步,并且值不是volatile。因此,严格来说, isSelected()如果从其设置的任何其他线程(即EDT,当用户按下按钮时)读取它,则可能返回垃圾)。或者我错了?

In every example I've seen, isSelected() is liberally queried from the main or whichever thread. But when I look at DefaultButtonModel's implementation, it's not synchronized, and the value is not volatile. So, strictly speaking, isSelected() could return garbage if it's read from any other thread than the one from which it's set (which is the EDT, when the user pushes the button). Or am I mistaken?

我最初想到这一点时,Bloch的Effective Java第66项令人震惊,这个例子:

I originally thought about this when shocked by item #66 in Bloch's Effective Java, this example:

public class StopThread {
    private static boolean stopRequested;

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            public void run() {
                int i = 0;
                while(!stopRequested) i++;
            }
        });
        backgroundThread.start();

        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}

与看起来相反,该程序永远不会终止,至少在某些机器上。从主线程更新 stopRequested 标志对后台线程是不可见的。这种情况可以通过同步的getter& amp;设置者,或设置标志 volatile

Contrary to what is seems, that program never terminates, on some machines at least. Updating the stopRequested flag from the main thread is invisible to the background thread. The situation can be fixed with synchronized getters & setters, or by setting the flag volatile.

所以:


  1. 在EDT之外查询Swing模型的状态(严格来说)是错误的吗?

  2. 如果没有,为什么会这样?

  3. 如果是,您如何处理?运气好,还是通过一些聪明的解决方法? InvokeAndWait?


推荐答案


  1. 不,没错,但与您需要确保提供适当的线程安全机制的任何跨线程通信(例如,使用 synchronized volatile )。例如,我通常编写自己的 TableModel 实现,通常位于 List< X> 其中 X 是我的业务对象。如果我打算让其他线程查询List,我将使它成为同步的 Collection 。值得注意的是,我通常不会从其他线程更新 List ;只查询它。

  2. 因为它与任何其他多线程应用程序的情况完全相同。

  3. 我通常会使集合同步(参见1 )。

  1. No, not wrong, but as with any cross-thread communication you need to ensure you provide appropriate thread-safety mechanisms if you decide to do this (e.g. use of synchronized or volatile). For example I typically write my own TableModel implementations, typically sitting on List<X> where X is my business object. If I intend for other threads to query the List I will make this a synchronized Collection. It's also worth noting I would never normally update the List from other threads; only query it.
  2. Because it's exactly the same situation as with any other multi-threaded application.
  3. I typically make the collection synchronized (see 1).

警告

尽管我的回答上面我通常直接在EDT之外访问模型。正如Carl所提到的,如果通过某些GUI动作调用执行更新的动作,则不需要执行任何同步,因为EDT已经运行了代码。但是,如果我希望执行一些导致模型被更改的后台处理,我通常会调用 SwingWorker ,然后分配 doInBackground的结果()来自 done()方法(即在EDT上)。这是更清洁的恕我直言,因为 doInBackground()方法没有副作用。

Despite my answer above I typically do not access models directly outside of the EDT. As Carl mentions, if the action of performing an update is invoked via some GUI action there's no need to perform any synchronization as the code is already being run by the EDT. However, if I wish to perform some background processing that will lead to the model being changed I will typically invoke a SwingWorker and then assign the results of doInBackground() from within the done() method (i.e. on the EDT). This is cleaner IMHO as the doInBackground() method has no side-effects.

这篇关于如果Swing模型的getter不是线程安全的,你如何处理它们?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆