2012-11-17 38 views
1

我遇到了非常當嘗試將多個字符串插入到具有TitledBorder的JTextPane時,出現了一個奇怪的問題(這很重要,問題似乎只發生在TitledBorder具體,其他邊界或根本沒有邊界工作正常)從線程。我的測試代碼(這個問題)顯著部分看起來是這樣的:將多個字符串插入帶有單個線程中的TitledBorder的JTextPane中鎖定導致程序鎖定

JTextPane myTextPane = new JTextPane(); 
myTextPane.setBorder(new TitledBorder("Some title")); 
StyledDocument doc = myTextPane.getStyledDocument(); 
SimpleAttributeSet sas = new SimpleAttributeSet(); 
StyleConstants.setForeground(sas, Color.BLACK); 

private void insertTwoStrings() 
{ 
    new Thread(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      docTest.insertString(docTest.getLength(), "first string ", sas); 
      docTest.insertString(docTest.getLength(), "second string\n", sas); 
     } 
    }).start(); 
} 

我們的問題:insertTwoStrings()方法工作正常有時,但有時它沒有在一個非常糟糕方式鎖定整個應用程序(我必須殺死進程關閉應用程序)。所以我在調試器中打開程序和複製的問題出現,當有問題的線程被鎖了,我暫停,並採取了在程序計數器位置仔細一看:

Current position of program counter

這樣看來,同步(這)是我的問題的原因。這實際上是一個錯誤還是我犯了一些錯誤?

如果有人想複製這一點,這個問題發生,你必須滿足以下三個條件:

  1. 從一個線程插入文本JTextPane中(即到其StyledDocument中的)
  2. 調用StyledDocument.insertString(...)多次內螺紋,不只是一次
  3. 的JTextPane中必須的TitledBorder

執行線程仍然有效有時,但時不時會失敗並鎖定整個程序。

+1

Swing組件不是線程安全的,只能在Event Dispatch Thread上訪問。所以你的代碼片段違反了擺動線程規則。 – Robin

+0

謝謝!當談到Swing時,我不是很有經驗,你能否指出我對於如何做到這一點的正確方向? – thousands

+0

- (糾正我也許我錯了),但我在另一個Java論壇上看到similair問題 – mKorbel

回答

4

正如其他人已經指出的Swing不是線程安全的,除非具體方法是記錄是線程安全的。 Swing提供了幾個可以將消息傳遞給事件分派線程的實用程序方法和類 - SwingUtilities包含invokeLater和invokeAndWait,SwingWorker線程可以將「完成」工作發送到回調函數。

// run will be executed on the EDT 
SwingUtilities.invokeLater(new Runnable() 
{ 
    @Override 
    public void run() 
    { 
     docTest.insertString(docTest.getLength(), "first string ", sas); 
     docTest.insertString(docTest.getLength(), "second string\n", sas); 
    } 
}); 

上面的代碼將執行鞦韆事件調度線程運行,所以要注意保持的run()短(快速閱讀),或您的用戶界面會慢如蝸牛。

+0

非常理解的答案,非常感謝! – thousands

2
  • 甚至Runnable#Thread是正確的方法,但從未通知EDT

意思與Document,模型何事JTextComponents

docTest.insertString(docTest.getLength(), "first string ", sas); 
docTest.insertString(docTest.getLength(), "second string\n", sas); 
  • 你有問題,與Concurency in Swing和常見的問題對於"ThreadSafe"方法,這個問題是/將/可能是相同的(通過使用普通的ThreadRunnable#Thread

  • 在Swing API實現例如)有wrapp docTest...invokeLater()

  • 不知道爲什麼會出現synchonized,則可以更好地利用invokeAndWait()

  • 通知invokeAndWait()必須從EDT中取出,如果在isEventDispatchThread之前測試過,否則導致(一些ecxeptions)鎖定當前的GUI,並且不能重用,並且在某些情況下必須關閉當前的JVM

  • 你可以使用SwingWorker,有很多方法可以很好地適應EDT, publish()process()done()

+0

使用SwingUtilities.invokeLater(..)工作,謝謝 – thousands