哪些 Swing 组件方法是线程安全的?

21
根据 Swing 教程:
一些 Swing 组件方法在 API 规范中被标记为“线程安全(thread safe)”,这些方法可以安全地从任何线程调用。所有其他 Swing 组件方法都必须从事件分派线程(event dispatch thread)中调用。忽略此规则的程序可能会大部分时间正常运行,但容易出现难以重现的不可预测错误。
那么这些被标记为“线程安全”的 Swing 组件方法是什么?实际上有吗?
更新/赏金:
是否有一个完整的线程安全的swing方法列表?(线程安全的 Swing 方法似乎很少,因此这样的列表不能太长...)

2
这个问题让我想到,您是否试图从多个线程操纵一个Swing GUI?如果是这样,您可能需要重新考虑设计,因为只要正确处理工作的卸载(例如使用某种形式的工作队列),就应该始终能够确保所有的Swing交互都仅发生在一个线程中。如果您这样做,就不需要担心Swing线程安全问题了... - mikera
5个回答

20

谷歌告诉我至少这些是线程安全的。以下是为情况提供概述,以防链接再次断开:


  • JTextPane
    • replaceSelection()
    • insertComponent()
    • insertIcon()
    • setLogicalStyle()
    • setCharacterAttributes()
    • setParagraphAttributes()




  • DefaultStyledDocument
    • insert():向文档中插入字符或字符串。
    • setLogicalStyle():为指定位置设置逻辑样式。
    • setCharacterAttributes():将一组字符属性应用于指定的字符范围。
    • setParagraphAttributes():将一组段落属性应用于指定的段落范围。

    • StyleContext
      • addAttribute():向给定的属性集添加一个属性。
      • addAttributes():向给定的属性集添加一组属性。
      • removeAttribute():从给定的属性集中移除一个属性。
      • removeAttributes():从给定的属性集中移除一组属性。
      • reclaim():释放内部缓存的属性集,以减少内存使用。

    • AbstractDocument
      • render():将文档的内容呈现到指定的图形上下文中。
      • remove():从文档中删除指定范围的内容。
      • insertString():向文档中插入字符或字符串。
      • createPosition():创建指向文档中指定偏移量位置的位置对象。

    • PlainDocument
      • insertString():向文档中插入字符或字符串。

    • HTMLDocument
      • setParagraphAttributes():将一组段落属性应用于指定的段落范围。

    2
    不用谢。这是一个有用的链接:http://www.googleguide.com/using_advanced_operators.html - BalusC
    1
    @Gili:我修复了链接。只需用大约半年前的download.oracle.com替换旧的java.sun.com URL即可。您也可以编辑答案而不是将其投票下降。坏链接完全是无意的。 - BalusC
    哦,JTextComponent的setText是线程安全的。这很有趣 :) 这意味着在许多情况下我不必再使用EDT了。不过我想知道,如果使用非官方LAF,它是否仍然是线程安全的? - Chris Dennett
    1
    一些信息已经过时。在Java 7中,JTextArea.append不再是线程安全的。 - Jarekczek
    1
    @Jarekczek:我在这里添加了Java 7更新链接 - trashgod

    7

    但是,哪些 Swing 组件方法被标记为“线程安全”?

    大多数 Swing 组件的方法都不是线程安全的。但有一些是线程安全的。要找出哪些是线程安全的,您只能查阅目标组件的 javadocs。 一个精心构建的谷歌搜索 可以加快这个过程。

    实际上有吗?

    确实有。一般来说,如果您正在使用 Swing 组件,则很可能需要调用既有线程安全又有非线程安全的方法。由于大多数方法都不是线程安全的,我更喜欢谨慎起见,以线程安全的方式执行所有操作。

    希望对您有所帮助。


    不是穷尽列表。

    DefaultStyledDocument:

    • 保护的 void insert(int offset, DefaultStyledDocument.ElementSpec[] data) throws BadLocationException
    • 公共的 void setLogicalStyle(int pos, Style s)
    • 公共的 void setCharacterAttributes(int offset, int length, AttributeSet s, boolean replace)
    • 公共的 void setParagraphAttributes(int offset, int length, AttributeSet s, boolean replace)

    javax.swing.text.AbstractDocument:

    • public void render(Runnable r):渲染指定的 Runnable。
    • public void remove(int offs, int len) throws BadLocationException:从文档中删除字符。
    • public void insertString(int offs, String str, AttributeSet a) throws BadLocationException:在文档中插入字符串。
    • public Position createPosition(int offs) throws BadLocationException:创建一个新的位置,该位置将在偏移量处标记文本。

    javax.swing.undo.UndoManager:
    类是线程安全的。


    3
    @BalusC 没有!在你得出结论之前,考虑到回答需要几分钟时间。 - bguiz
    哇,太好了!对我来说这是一个很棒的信息。因为现在我正在尝试使用SWING工作。 :D - gumuruh

    5

    查找带有“is thread safe”注释的Java文档和源代码中的类列表如下:

    JEditorPane
    JTextArea
    AbstractDocument
    DefaultCaret
    DefaultStyledDocument
    JTextComponent    
    PlainDocument
    StyleContext    
    HTMLDocument
    UndoManager
    

    这并不意味着在src中没有其他已记录或未记录的线程安全内容。

    我认为这是一个相当奇怪的问题,但大多数组件都被视为是线程安全的,因为Swing是单线程模型,所有更新都需要在事件分发器线程上进行,这很容易实现。


    4
    但是您已经有了答案:只有那些在方法的JavaDoc中明确记录为线程安全的方法,才是线程安全的!这来自于JTextComponent.setText
     * This method is thread safe, although most Swing methods
     * are not. Please see 
     * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
     * to Use Threads</A> for more information.     
    
    如果方法文档没有说明它是安全的,那么它就不是安全的:因此,在编写Swing代码时访问JavaDoc至关重要。

    1
    是的,这是隐含的答案,但仍然不是线程安全方法列表。 - Joonas Pulakka
    你问了“有没有”,我给了一个例子。嗯。 - oxbow_lakes
    还有一些方法没有记录为线程安全,但可以从其他线程调用。至少我是这么认为的。例如,java.awt.Window类中的dispose()方法可以被任何线程调用,因为该方法本身创建了一个可运行对象,该对象会发送到EDT。当然,你可能会争辩说dispose()是AWT方法而不是Swing方法,但它在Swing中被经常使用,值得一提。 - Alderath

    4

    Java 7中,一些以JTextComponent为根的视图组件方法被错误地标记为线程安全;它们现在已经被取消标记或正确地标记为线程安全。使用EventQueue.invokeLater()的典型解决方法在这里显示。其余与模型相关的方法在此处及以下列表中应该进行严格审查,理由在此处概述。 JTextArea::append是一个具体的示例


    • JTextComponent(JTextComponent类)
    • replaceSelection()(替换选择内容)
    • setText()(设置文本内容)
    • print()(打印)
    • getPrintable()(获取可打印对象)

    • JTextPane(文本面板)
    • replaceSelection()(替换选中内容)
    • insertComponent()(插入组件)
    • insertIcon()(插入图标)
    • setLogicalStyle()(设置逻辑样式)
    • setCharacterAttributes()(设置字符属性)
    • setParagraphAttributes()(设置段落属性)


    嗯...为什么?刚刚查看了JTextComponent的方法,前两个不保证线程安全,与打印相关的方法会阻塞调用线程。如果我没记错的话(没有重新检查),现在除了repaint和revalidate(它们保证必要时将请求发布到EDT)之外,没有任何东西是线程安全的。 - kleopatra
    哦...也许我误解了你的意图:这是旧列表减去这里列出的方法吗?如果是这样,那么列出仍然被记录为线程安全的方法可能会更少令人困惑(至少对我来说是这样的 :))。 - kleopatra
    @kleopatra: 我不能不同意 - 这很令人困惑!我正在寻找一个共同点(无意双关语:-),看起来受影响的是视图组件。我选择专注于需要审查的潜在向上迁移问题列表,而不是预先防范原始答案 - trashgod
    1
    这些方法以前并不是“线程安全的”,它们的文档错误地声称具有线程安全性,并已修复以适应实际实现(未更改)。例如,请参见https://bugs.openjdk.java.net/browse/JDK-4765383。 - Holger
    @Holder:我同意,已更新,感谢引用。 - trashgod

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接