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

yan*_*isf 5 java concurrency swing multithreading event-dispatch-thread

SwingWorker javadoc中提到了上述语句.

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

难道会发生什么坏事吗?

Kev*_*ede 6

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

您见过的应用程序可能在大多数情况下都可以工作,甚至可能在某些环境中一直有效.但是当它不起作用时,它将以非常奇怪的方式失败,难以重现.


Uli*_*Uli 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);
   }
Run Code Online (Sandbox Code Playgroud)

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