私はDocument
のスレッドの安全性を信じることについて警告する経験豊かな人を信頼します。しかし、アプリケーションがこの問題を簡単に悪用すると信じるのは難しいので、何も表示しないでください。JTextArea
おそらく、append
以外のいくつかの方法が使用され、一般的な障害が発生する可能性があります。私はDebian上でOracle jre 6(そしてJava 6 64bitでWin7)を実行しても問題ないと思うテストアプリケーションを添付します。
- を誤挿入配置とさえ
BadLocationException
Sの結果getLength()
とinsertString()
方法を同期しない:私は含まれいくつかのミスを修正した開発プロセスの間に 。他のスレッドは、これらの2つの命令の間で文書を修正していました。たとえ同じライン上にあったとしても:
- 嚥下
BadLocationException
。私はそれを打つことは不可能だと確信していたが、間違っていた。
getLength()
とinsertString()
ペアのためのクリティカルセクションを作成する上で、特に必要性を実現した後、それは(see Tom Hawtin's answer here)JTextArea
が失敗することは明らかです。そして、実際には、insertString
がすべて正常に実行されたわけではなく、結果として得られるテキストが、それよりも短くなっていたからです。しかし、この問題はループカウント10000では100000でしか発生しませんでした。jdk 7 code of JTextArea.appendを調べてみると、基礎となる文書を変更するだけで、外部で同期するのはJTextArea
となります。
0に挿入すると、同期することなく正常に動作しましたが、完了までに時間がかかりました。
通常、このようなアプリケーションでは、最後の行までスクロールします。ねえ、これはまあまあです。あなたはEDTのうちsetCaretPosition
できません。だから私はしません。手動でスクロールします。スクロールを解決するための私の提案はanother answerです。
あなたのシステムでこのアプリケーションの問題が発生した場合は、コメントしてください。私の結論はDocument.insertString
はスレッドセーフですが、効果的に使用するにはgetLength
と一緒に同期が必要です。次のコードPlainDocument
において
は、ロックにgetLength
とinsertString
をラップ同期append
方法を作成するためにサブクラス化されています。このロックは保護されたアクセス権を持っているため、別のクラスなしでは使用できませんでした。しかし、外部同期によっても正しい結果が得られました。
ご参考までに非常に多くの編集がありました。最後に、より多くのことを学んだ後、この答えを再構成しました。
コード:
import java.awt.*;
import java.util.concurrent.CountDownLatch;
import javax.swing.*;
import javax.swing.text.*;
class SafePlainDocument extends PlainDocument
{
public void append(String s)
{
writeLock();
try {
insertString(getLength(), s, null);
}
catch (BadLocationException e) {
e.printStackTrace();
}
finally
{
writeUnlock();
}
}
}
public class StressJText
{
public static CountDownLatch m_latch;
public static SafePlainDocument m_doc;
public static JTextArea m_ta;
static class MyThread extends Thread
{
SafePlainDocument m_doc;
JTextArea m_ta;
public MyThread(SafePlainDocument doc)
{
m_doc = doc;
}
public void run()
{
for (int i=1; i<=100000; i++) {
String s = String.format("%19s %9d\n", getName(), i);
m_doc.append(s);
}
StressJText.m_latch.countDown();
}
}
public static void main(String sArgs[])
{
System.out.println("hello");
final int cThreads = 5;
m_latch = new CountDownLatch(cThreads);
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
m_ta = new JTextArea();
m_doc = new SafePlainDocument();
m_ta.setDocument(m_doc);
m_ta.setColumns(50);
m_ta.setRows(20);
JScrollPane scrollPane = new javax.swing.JScrollPane();
scrollPane.setViewportView(m_ta);
frame.add(scrollPane);
frame.pack();
frame.setVisible(true);
for (int it=1; it<=cThreads; it++) {
MyThread t = new MyThread(m_doc);
t.start();
}
}
});
try {
m_latch.await();
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
System.out.println("tf len: " + m_ta.getText().length());
System.out.println("doc len: " + m_doc.getLength());
System.exit(0);
}
});
}
}
EDTについて説明する良いチュートリアルはありますか? –
私の答えの編集を参照してください。 –
ありがとうございました:) –