【问题标题】:Swing Thread Violation摆动线程违规
【发布时间】:2015-04-29 23:34:20
【问题描述】:

在 Swing 中调试一个奇怪的行为时,我发现了这个工具: CheckThreadViolationRepaintManager 由 Alex Ruiz 编辑的版本。 (在回答我的问题之前,您必须了解该课程的作用,谢谢)

我在我的代码中发现了线程冲突,但我不明白为什么,因为我到处都使用 SwingUtilities.invokeAndWait()。

这是导致线程冲突的代码。只有最后一行导致错误:

protected void display() {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            asyncDisplay();
        }
    });
}

private void asyncDisplay(){
   System.out.println("is in edt: " + SwingUtilities.isEventDispatchThread());
    this.printedComponent.setVisible(true);
    this.printedComponent.setOpaque(false);
    this.setVisible(true);
}

结果:

is in edt:  true
exception: java.lang.Exception
java.lang.Exception
at fr.numvision.common.CheckThreadViolationRepaintManager.checkThreadViolations(CheckThreadViolationRepaintManager.java:31)
at fr.numvision.common.CheckThreadViolationRepaintManager.addDirtyRegion(CheckThreadViolationRepaintManager.java:25)
at javax.swing.JComponent.repaint(JComponent.java:4795)
at java.awt.Component.imageUpdate(Component.java:3516)
at javax.swing.JLabel.imageUpdate(JLabel.java:900)
at sun.awt.image.ImageWatched$WeakLink.newInfo(ImageWatched.java:132)
at sun.awt.image.ImageWatched.newInfo(ImageWatched.java:170)
at sun.awt.image.ImageRepresentation.setPixels(ImageRepresentation.java:533)
at sun.awt.image.ImageDecoder.setPixels(ImageDecoder.java:126)
at sun.awt.image.GifImageDecoder.sendPixels(GifImageDecoder.java:447)
at sun.awt.image.GifImageDecoder.parseImage(Native Method)
at sun.awt.image.GifImageDecoder.readImage(GifImageDecoder.java:596)
at sun.awt.image.GifImageDecoder.produceImage(GifImageDecoder.java:212)
at sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:269)
at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:205)
at sun.awt.image.ImageFetcher.run(ImageFetcher.java:169)

我真的不明白为什么 this.setVisible(true); 会导致线程冲突(这是一个 JComponent)而 this.printedComponent.setVisible(true); 不会。

谢谢,

【问题讨论】:

  • 如果调用 setVisible 的线程不是 EDT,则会导致违规。最后一行可能导致它的原因,因为它可能是将组件连接到本机对等点并启动重绘过程滚动的方法,但这都是猜测工作,需要一个可运行的示例来确定
  • @MadProgrammer 请阅读 OPs 问题和我的 cmets 由 Marko Topolnik 回答
  • 你有CheckThreadViolationRepaintManager 类以及它是如何安装的?
  • 考虑提供一个runnable example 来证明您的问题。这将导致更少的混乱和更好的响应。另外,请记住,对repaint 的调用不必在 EDT 的上下文中进行。因为将 post 的绘制事件重新绘制到事件队列中,所以实际的绘制操作将在 EDT 内发生...
  • 你在任何地方使用ImageIcon吗?

标签: java swing event-dispatch-thread invokeandwait repaintmanager


【解决方案1】:

导致异常的代码与您的this.setVisible(true); 行不同步。该行只是将组件标记为需要重新绘制,实际的重新绘制事件稍后会出现,setVisible() 已返回。似乎正在发生的事情是一些其他代码,不知何故与您的组件的重新绘制有因果关系,将一些 GUI 代码提交给外部线程。

这一切的细节不可能从你发布的代码量中得出。

【讨论】:

  • SwingUtilities.invokeAndWait() causing an exception in the case that EDT returns true,必须在 EDT 外使用,the same for paintImmediatelly,两者都可以返回严重的异常(当 RepaintManager 可以锁定当前 JVM == addept 仅用于来自 TaskManager 的杀戮时)
  • 代码应该是,必须是 if (!isEDT) use invokeAndWait() else use invokeLater() :-)
  • 请在此处删除此答案
  • 我还在试图弄清楚你在说什么:)
  • Ok Marko,所以从 EDT 调用的“this.setVisible(true)”会导致其他地方的代码(但仍在 EDT 中执行)在 EDT 之外执行一些 GUI 操作?!做到这一点的唯一方法是在新线程中启动 GUI 操作,我不这样做。