为什么只应在Event Dispatch Thread上访问Swing组件?

时间:2015-02-26 07:39:05

标签: java multithreading swing concurrency event-dispatch-thread

SwingWorker javadoc中提到了上述语句。

在一个应用程序中,我看到一个冗长的后台任务在一个不同的线程中运行并且更新UI也没有问题(可以访问对Swing组件的引用)。

可能会发生不好的事情吗?

2 个答案:

答案 0 :(得分:6)

这是因为Java memory model不保证一个线程的内存写入对其他线程可见,除非您使用某种形式的同步。为了性能和简单性,Swing不同步。因此,其他线程的写入可能永远不会被EDT看到。

您看过的应用程序大部分时间都可以正常运行,甚至可能在某些环境中一直运行。但是当它不起作用时,它会以一种难以复制的奇怪方式失败。

答案 1 :(得分:5)

实现所有Swing组件以从单个线程(事件调度线程)访问。因此,对变量和字段的并发访问和并发更改没有任何保护。

如果你很幸运,一切都很顺利。但是你不能依赖它,同样的代码在下次运行时可能会遇到大量问题。

一个简单的例子:

JLabel的绘制过程包含以下(简化)代码(取自BasicLabelUI类):

   # assume your label is enabled
   Icon icon = (label.isEnabled()) ? label.getIcon() : label.getDisabledIcon();

   # what happens if another thread calls label.setEnabled(false) at this point?

   if (icon != null) {
      icon.paintIcon(c, g, paintIconR.x, paintIconR.y);
   }

   if (label.isEnabled()) {
         paintEnabledText(label, g, clippedText, textX, textY);
   }
   else {
         paintDisabledText(label, g, clippedText, textX, textY);
   }

例如,如果从EDT之外的其他线程调用setEnabled(),则可能会获得带有启用图标但禁用的绘制文本的标签。