java - 尝试在 JTextArea 中使用 BufferedWriter 时发生并发冲突

标签 java swing concurrency

我在输出到 JTextArea 时遇到某种线程问题。我设置了一个 BufferedWriter 来写入此文本区域,但由于某种原因,在当前函数完成之前它不会写入此区域。例如,我有这样的代码,用于检查 URL 列表以查看它们是好还是坏:

for( final String s : urls ){
    String sContent = IO.getURLContent( s );
    if( sContent == null ){
        writeLine( "Error " + s );
    } else {
        writeLine( "Worked " + s );
    }
}

void writeLine( String sLineText ) throws java.io.IOException {
    mbwriter.write(sLineText);
    mbwriter.newLine();
    mbwriter.flush();
}

输出仅在循环完成后发生,即使在检查每个 URL 后刷新写入器。我尝试将 IO 操作放在一个单独的线程中,如下所示:

for( final String s : urls ){
SwingUtilities.invokeLater( new Runnable() {
    public void run(){
        String sContent = IO.getURLContent( s );
            if( sContent == null ){
                writeLine( "Error " + s );
            } else {
                writeLine( "Worked " + s );
            }
        }
    }
} );
}

但这没有什么区别,输出仍然被阻塞,直到整个循环完成。

请注意,整个 Swing 界面在此操作期间挂起。你无法点击任何东西,甚至是靠近的窗口。界面完全卡住。

最佳答案

这是预料之中的。

Swing 是单线程环境,也就是说,如果您通过长时间运行的进程或 block 方法调用来阻塞事件调度线程,它将无法处理发布到事件队列的新事件,从而有效地使您的 UI“挂起”

听起来您的第一个示例正在 EDT 的上下文中运行,而您的第二个示例仍在 EDT 的上下文中运行,但计划在将来的某个时间(在 EDT 能够更新之后)进行更新,再次处理事件队列...

invokeLater 正在事件队列上放置一个事件,以便 EDT“稍后”处理

考虑使用 SwingWorker,它提供了在后台运行代码的能力,但提供了允许您通过其 publish 同步更新到 EDT 的方法,并且处理方法

参见Concurrency in SwingWorker Threads and SwingWorker了解更多详情

举个例子...

public class URLWorker extends SwingWorker<List<String>, String> {

    private List<String> urls;
    private BufferedWriter bw;

    public URLWorker(List<String> urls, BufferedWriter bw) {
        this.urls = urls;
        this.bw = bw;
    }

    @Override
    protected void process(List<String> chunks) {
        for (String result : chunks) {

            try {
                bw.write(result);
                bw.newLine();
            } catch (IOException exp) {
                firePropertyChange("error", null, ex);
            }

        }
        try {
            bw.flush();
        } catch (IOException ex) {
            firePropertyChange("error", null, ex);
        }
    }

    @Override
    protected List<String> doInBackground() throws Exception {
        List<String> results = new ArrayList<String>(urls.size());
        for (final String s : urls) {
            String sContent = IO.getURLContent(s);
            StringBuilder result = new StringBuilder(s);
            if (sContent == null) {
                result.insert(0, "Error ");
            } else {
                result.insert(0, "Worked ");
            }
            publish(result.toString());
            results.add(result.toString());
        }
        return results;
    }
}

关于java - 尝试在 JTextArea 中使用 BufferedWriter 时发生并发冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26518671/

相关文章:

java - SolrCore初始化失败-最大直接内存可能太低

java - 在 Java Maven 项目中通过 Spark 查询 Cassandra 中的数据

java - Java 中的线程 : How to lock an object?

java - JBoss 缓存配置

java - 如何启动不阻塞Java主线程的后台线程?

java - Standalone.xml 和standalone-full.xml 之间的区别

java - 如何从 java 应用程序连接到 PCF 并列出组织、空间、应用程序及其配置?

Java:WAITING第一帧,同时从第二帧检索数据,然后点击关闭按钮,控件也进入第一帧

java swing - 在 java swing 中创建一个类似旋转木马的按钮

java - 将 JFormattedTextField 中的多个值分配给多个变量