1

スレッドから TitledBorder を持つ JTextPane に複数の文字列を挿入しようとすると、非常に奇妙な問題が発生しました (これは重要です。問題は、特に TitledBorder でのみ発生するようで、他の境界線または境界線がまったく機能しないようです)。(この問題の) テスト コードの重要な部分は次のようになります。

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() メソッドは時々うまく動作しますが、アプリケーション全体をロックする方法で非常にひどく失敗することもあります (アプリケーションをシャットダウンするにはプロセスを強制終了する必要があります)。そこで、デバッガーでプログラムを開き、そこで問題を再現しました。問題のあるスレッドがロックされたときに中断し、プログラム カウンターの位置を詳しく調べました。

プログラムカウンターの現在位置

この同期(これ)が私の問題の原因のようです。これは実際にはバグですか、それとも私は何らかの間違いを犯していますか?

誰かがこれを再現したい場合、問題が発生するには、次の 3 つの基準をすべて満たす必要があります。

  1. Thread からJTextPane (つまり、StyledDocument) にテキストを挿入する
  2. StyledDocument.insertString(...) をスレッド内で 1 回だけでなく複数回呼び出す
  3. JTextPane には TitledBorder が必要です

スレッドの実行はまだ機能する場合がありますが、時々失敗してプログラム全体がロックされます。

4

2 に答える 2

4

他の人がすでに指摘しているように、特定のメソッドがスレッドセーフであると文書化されていない限り、Swing はスレッドセーフではありません。Swing には、イベント ディスパッチ スレッドにメッセージを渡すことができるいくつかの Utility メソッドとクラスが用意されています。

// 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);
    }
});

上記のコードは、swings イベント ディスパッチ スレッドで run を実行するため、run() を短くする (読み取りが速くなるようにする) ように注意してください。そうしないと、ユーザー インターフェイスが遅くなります。

于 2012-11-17T15:50:15.757 に答える
2
  • 方法は適切ですが、Runnable#ThreadEDT に通知されなかった一般的な問題

、 JTextComponentsDocumentのモデルで何かを意味します

docTest.insertString(docTest.getLength(), "first string ", sas);
docTest.insertString(docTest.getLength(), "second string\n", sas);
  • Swing"ThreadSafe"の同時実行に問題があり、この問題は、setText("")プレーンThreadまたはRunnable#Thread

  • ラップdocTest...する必要がありますinvokeLater()

  • なぜそこにあるのかわからないsynchonized、それから使用する方が良いかもしれませんinvokeAndWait()

  • 注意invokeAndWait() は EDT から呼び出され、isEventDispatchThread以前にテストされた場合はテストされる必要があり、それ以外の場合は (いくつかの例外) 現在の GUI がロックされ、再利用できず、場合によっては現在の JVM を閉じる必要があります

  • を使用することができSwingWorkerます。EDT をかなり適切にモチーフにpublish()した方法がprocess()あります。done()

于 2012-11-17T15:32:16.713 に答える