Java 使Swing组件同步

Java 使Swing组件同步,java,multithreading,swing,Java,Multithreading,Swing,我正在读Oaks和Wong的《Java线程》第三版(O'Reilly 2004)。 书中到处都有挥杆打字游戏的例子。 他们定义的类大多是javax.swing.JComponent的自定义子类 我觉得非常错误的是,他们使用各种同步方法使那些JComponents线程安全。我的印象是Swing组件不应该是线程安全的,而是应该始终从Swing事件调度线程访问它们。(有趣的是,他们通过Swing EDT修改组件的次数很少,其中之一是针对setText,这是极少数不需要从EDT调用的Swing方法之一。

我正在读Oaks和Wong的《Java线程》第三版(O'Reilly 2004)。 书中到处都有挥杆打字游戏的例子。 他们定义的类大多是
javax.swing.JComponent
的自定义子类

我觉得非常错误的是,他们使用各种同步方法使那些
JComponent
s线程安全。我的印象是Swing组件不应该是线程安全的,而是应该始终从Swing事件调度线程访问它们。(有趣的是,他们通过Swing EDT修改组件的次数很少,其中之一是针对
setText
,这是极少数不需要从EDT调用的Swing方法之一。)

我想从你们中的一些人那里了解一下,他们有很多编写/阅读Swing代码的经验: 程序员经常使Swing组件同步,而不是总是通过EDT修改它们吗?可以忍受吗

编辑:
我注意到这几乎是同一个问题。然而,它并没有说明程序员在野外实际做什么。我对O'Reilly的书会如此公然违反Swing线程模型感到困惑

编辑:
我发现他们在书中的某个地方简单地解释了摆动线程模型。尽管如此,我还是想回答我的问题。我觉得读过这本书的大多数人最终都会违反Swing线程模型,因为他们的大多数示例都会这样做

编辑:
如果您想查看代码,可以将其作为zip文件。请参见示例ch03/example1/AnimatedCharacterDisplayCanvas

编辑:
我刚刚了解到,
setText
在Java7(2011年7月发布)中不会是线程安全的“Swing组件本身不是线程安全的,一般来说,在屏幕上显示Swing组件后,您只能从事件线程安全地修改它们的数据。如果从事件调度线程以外的任何线程修改Swing组件数据,则必须采取预防措施以确保数据完整性。此规则的一个例外是JTextComponent或其任何子类上的setText方法,或其文档明确声明为线程安全的任何Swing组件方法。” 莫妮卡·波兰

您永远不应该在Swing组件上有同步块,它在尝试渲染时会导致奇怪的问题

Swing不是线程安全的,因为所有内容都应该在EDT上更新,甚至创建Swing组件


长时间运行的进程应移动到后台线程或SwingWorker。当EDT以外的线程需要制作组件或更新组件时,应使用SwingUtilities.invokeLater()对其进行包装

简单地说,只要同步方法不在上执行,它们就不会阻止事件分派线程。相反,在另一个线程上执行的方法应始终使用通过调用器()分派代码,或相关机制,如或。从实际情况来看,这些机制是可靠的。示例可能是正确的,但应从这个角度进行检查

API说,“唯一的要求是 在我看来,这相当于事件的“发生在”关系
和JLS。可能会找到更详细的讨论。

我总是确保在EDT上完成更新。你错了:
setText
必须从EDT调用!@jfpoilpret它是线程安全的。所有
JTextDocument
都包含一个内部
AbstractDocument
,它有一个写锁。无论你调用
由于必须获得锁,因此EDT中的setText
与否没有任何区别。(
getText
不是线程安全的。)仔细想想:在EDT上调用
setText
可能是一个坏主意,因为它可能会在等待文档锁定时卡住。我的错误!你是对的,感谢你指出这一点,我确信
setText
与大多数Swing方法一样。现在我不明白为什么
JTextComponent
是这样实现的是的,如果Swing EDT正在等待锁定,那么整个GUI都将被锁定。但是,对于书中的简单示例,我认为这不是一个问题(我没有尝试运行代码)。Swing组件仍然没有理由持有锁定。因为它是单线程的(EDT)竞争条件是不可能的。在Swing应用程序中对类进行锁定是可以的,但不应从EDT-1调用它们。引用的文章已过时(2001)。Sun最近(2009或2010)使线程安全声明更具一般性:即使组件创建也必须在EDT中完成。是的,但这本书在2004年之前出版,答案是针对这一特定情况。在这本书中,它们同步
paintComponent
,因为它访问一个被其他线程修改的对象。它们还同步修改此对象的方法。我认为他们所做的工作是有效的;这只是因为它不尊重Swing线程模型。如果示例变得更复杂,那么在不让GUI变得迟钝的情况下维护同步可能会变得一团糟(这就是没有多线程GUI的原因)。它们不使用
invokeLater
invokeAndWait
。例如,某些线程生成一个随机字符,该字符通过该组件的同步setter方法设置为
JComponent
的成员。该组件的
paintComponent
也会同步,因为它会打印出char成员。我猜我的最简单的问题是:有人见过synchron吗