Я доверяю опытным ребятам, которые предупреждают о том, что верят в безопасность потока Document
. Однако трудно поверить, что приложение использует эту проблему настолько легко, что в JTextArea
ничего не отображается. Возможно, используются некоторые другие методы, кроме append
, и они вызывают общий сбой. Я прикрепляю тестовое приложение, которое я запускаю на Debian с Oracle jre 6 (а также Win7 с java 6 64 бит) и не вижу проблем.
В процессе разработки я должен был исправить несколько ошибок, которые включали:
- Не синхронизации
getLength()
и insertString()
метода, который привел к неправильному размещению вставки и даже BadLocationException
сек. Другие темы изменяли документ между этими двумя инструкциями. Даже если они были на одной линии :)
- Глотание
BadLocationException
. Я был уверен, что это невозможно, но это было неправильно.
После реализации описанной выше, особенно необходимость создания критической секции для getLength()
и insertString()
пары, то очевидно, что JTextArea
потерпит неудачу (see Tom Hawtin's answer here). И я видел, что это действительно так, потому что не каждый insertString
был успешно выполнен, а полученный текст был короче, чем следовало бы. Однако эта проблема не возникла с числом циклов 10000, только на 100000. И глядя в jdk 7 code of JTextArea.append, который ничего не делает, кроме изменения базового документа, похоже, что и внешняя синхронизация JTextArea
.
Вставка в 0 также хорошо работает, без какой-либо синхронизации, хотя для ее завершения потребовались целые вековые годы.
Обычно в таких приложениях требуется прокрутить до последней строки. Эй, это не так. Вы не можете setCaretPosition
из EDT. Так что я этого не делаю. Прокрутка вручную. Мое предложение разрешить прокрутку находится в another answer.
Если вы видите проблемы с этим приложением в вашей системе, прокомментируйте. Я пришел к выводу, что 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);
}
});
}
}
Можете ли вы упомянуть о любых хороших учебниках, объясняющих EDT? –
См. Редактирование в моем ответе. –
Спасибо большое :) –