java - 如果 Swing 模型的 getter 不是线程安全的,您将如何处理它们?

标签 java swing thread-safety

众所周知,更新 Swing GUI 必须专门在 EDT 中完成。更少的广告是阅读来自 GUI 的内容必须/应该在 EDT 中完成。例如,我们以 ButtonModel's isSelected() 为例方法,它告诉(例如)ToggleButton 的状态(“向下”或“向上”)。

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

当我对 Bloch 的 Effective Java 中的第 66 项感到震惊时,我最初想到了这个,这个例子:

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 和 setter 或通过设置标志 volatile 来解决。

所以:

  1. 在 EDT(严格来说)之外查询 Swing 模型的状态是否错误?
  2. 如果不是,怎么会?
  3. 如果是,您如何处理?是靠运气,还是靠一些聪明的解决方法?调用并等待?

最佳答案

  1. 不,没有错,但是与任何跨线程通信一样,如果您决定这样做(例如使用 synchronizedvolatile),您需要确保提供适当的线程安全机制。例如,我通常自己编写 TableModel实现,通常位于 List<X>其中 X是我的生意对象。如果我打算让其他线程查询列表,我会将其设为同步 Collection .同样值得注意的是,我通常永远不会更新 List来自其他线程;只查询它。
  2. 因为它与任何其他多线程应用程序的情况完全相同。
  3. 我通常使集契约(Contract)步(参见 1)。

警告

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

关于java - 如果 Swing 模型的 getter 不是线程安全的,您将如何处理它们?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2092050/

相关文章:

java - 如何生成特定位置上的数字必须在特定范围内的数字?

java - Ajax 文件上传存储字节直到保存 java.lang.

java - 更改 JTable 单元格背景颜色

C++11 具有原子属性的结构体定义

python - ThreadPoolExecutor 线程数

c++ - 退出应用程序前关闭线程

java - JDBC 将 Boolean 转换为 mySQL 兼容的 Boolean 类型

java - 基本 2D 寻路(无需图表)

java - 为 JTable 创建多行标题

java - JTextField只显示绝对值,没有负号?