Document
私は、スレッドセーフを信じることについて警告する経験豊富な人を信頼しています。ただし、アプリケーションがこの問題を簡単に悪用して、何も表示されないということは信じられJTextArea
ません。たぶん、他のいくつかの方法が使用されますがappend
、それらは一般的な失敗を引き起こします。Oracle jre 6を搭載したDebian(およびjava 6 64ビットを搭載したWin7)で実行するテストアプリを添付しましたが、問題はありません。
開発プロセス中に、次のようないくつかの間違いを修正する必要がありました。
- 同期がとれておらず
getLength()
、insertString()
挿入の配置が間違っていて、さらにはBadLocationException
sが発生した方法。他のスレッドは、これら2つの命令の間でドキュメントを変更していました。それらが同じ行にあったとしても:)
- 飲み込む
BadLocationException
。打つことは不可能だと確信していましたが、間違っていました。
上記、特にgetLength()
とペアのクリティカルセクションを作成する必要性を認識した後、それが失敗することはinsertString()
明らかです(ここでトムホーティンの答えを参照してください)。そして、すべてが正常に実行されたわけではなく、結果のテキストが本来よりも短かったため、実際に実行されたことがわかりました。ただし、この問題はループカウント10000では発生せず、100000のみでした。また、基になるドキュメントを変更するだけのJTextArea.appendのjdk 7コードを調べると、外部で同期することもできるようです。JTextArea
insertString
JTextArea
0での挿入も、同期なしでうまく機能しましたが、完了するまでに何年もかかりました。
通常、このようなアプリケーションでは、最後の行までスクロールする必要があります。ねえ、これはawtです。setCaretPosition
EDTから抜け出すことはできません。だから私はしません。手動でスクロールします。スクロールを解決するための私の提案は別の答えにあります。
システムでこのアプリケーションに問題が発生した場合は、コメントしてください。私の結論は、Document.insertString
スレッドセーフであるということですが、それを効果的に使用するにはgetLength
、同期が必要です。
次のコードPlainDocument
では、同期メソッドを作成するためにサブクラス化されています。append
このメソッドは、ラップgetLength
しinsertString
てロックになります。このロックはアクセスを保護しているので、別のクラスなしでは使用できませんでした。ただし、外部同期でも正しい結果が得られました。
ところで:多くの編集をしてすみません。最後に、私はさらに学んだ後、この答えを再構築しました。
コード:
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);
}
});
}
}