JEditorPaneHTMLEditorKitParserMethodReadPending读取挂起

wen java案例 1

本文目录导读:

JEditorPaneHTMLEditorKitParserMethodReadPending读取挂起

  1. 问题本质
  2. 常见原因
  3. 解决方案
  4. 诊断方法

你提到的 JEditorPaneHTMLEditorKitParserMethodReadPending 并不是一个标准的 Java API 方法或类名,而很可能是 堆栈跟踪(stack trace)日志输出 中的一段缩写/简化信息,通常出现在使用 JEditorPaneHTMLEditorKit 解析 HTML 时遇到的线程阻塞或挂起问题。

该信息通常对应真实类:
javax.swing.text.html.HTMLEditorKit$Parserjavax.swing.text.html.parser.ParserDelegator
以及内部回调方法如 read()parse() 或某种挂起状态。


问题本质

JEditorPane 使用 HTMLEditorKit 解析 HTML 时,解析器会在 EDT(事件分发线程) 上同步解析内容。

  • HTML 内容过大
  • HTML 结构复杂(嵌套过深、格式错误)
  • 遇到某些特定标签(如 <script><object><iframe>)时尝试加载外部资源
  • 或解析器本身在回调时因同步锁、死锁、网络读取被阻塞

就会导致 EDT 被阻塞 → 界面冻结 → 出现类似 ReadPending(读取挂起)的状态。


常见原因

解析器在 EDT 上同步读取

JEditorPane editor = new JEditorPane();
editor.setEditorKit(new HTMLEditorKit());
editor.setText("<html>大量或复杂HTML内容</html>");
  • setText 会立即解析 → 如果内容大 → 阻塞 EDT

遇到需要远程加载的资源

<img src="http://..."><link href="...">
如果不设置 HTMLEditorKitImageTracker 或忽略外部资源,解析器会尝试建立连接 → 导致挂起

解析器内部锁竞争

HTMLEditorKit 使用 单例解析器ParserDelegator),内部有同步块。
多个 JEditorPane 同时解析 → 一个正在解析,其他挂起等待。

SwingWorker 或线程误用

如果在非 EDT 线程设置 setText(),Swing 会 invokeLater 到 EDT,但如果此时 EDT 已被前一次解析阻塞 → 新的任务累积 → 表现为“pending”


解决方案

✅ 方案一:避免在 EDT 上解析大 HTML

将 HTML 解析移到后台线程,解析完成后在 EDT 上设置纯文本(已渲染结果)

SwingWorker<String, Void> worker = new SwingWorker<>() {
    @Override
    protected String doInBackground() throws Exception {
        // 使用非 Swing 解析器(如 Jsoup)在后台解析
        org.jsoup.Jsoup.parse(htmlText).text();  // 只提取文本
        // 或自定义轻量解析
    }
    @Override
    protected void done() {
        try {
            String plainText = get();
            editor.setText(plainText);  // 普通文本,无需HTML解析
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
};
worker.execute();

✅ 方案二:自定义 HTMLEditorKit,移除外部资源加载

HTMLEditorKit kit = new HTMLEditorKit() {
    @Override
    public ViewFactory getViewFactory() {
        return new HTMLFactory() {
            @Override
            public View create(Element elem) {
                // 对 IMG 等标签返回空 View
                if (elem.getName().equals("img")) {
                    return new ComponentView(elem);
                }
                return super.create(elem);
            }
        };
    }
};
editor.setEditorKit(kit);

✅ 方案三:使用 DocumentFilter + 异步设置

先创建一个空的 HTMLDocument,然后用 SwingWorker 解析 HTML 并填充文档:

HTMLDocument doc = (HTMLDocument) editor.getDocument();
SwingWorker<Void, Void> worker = new SwingWorker<>() {
    @Override
    protected Void doInBackground() {
        // 在后台线程完成复杂解析
        // 使用 ParserDelegator 的 parse 方法,并传入空的 HTMLEditorKit.ParserCallback
        return null;
    }
    @Override
    protected void done() {
        // 在 EDT 设置最终结果
    }
};
worker.execute();

✅ 方案四:减小 HTML 复杂度

  • 拆分大 HTML 为多个小段落,分批设置到 JEditorPane
  • 避免使用 <table><div> 嵌套超过 10 层
  • 禁止 <script><iframe> 等标签

✅ 方案五:使用 javax.swing.text.html.parser.ParserDelegator 时确保不会多次同时解析

// 使用全局锁
synchronized (ParserDelegator.class) {
    parser.parse(reader, callback, true);
}

诊断方法

如果出现挂起,可通过以下方式确认原因:

堆栈快照

在挂起时用 jstack 或 IDE 的线程视图查看:

"EDT" #1 prio=5 os_prio=0 cpu=... tid=...
   at java.net.SocketInputStream.socketRead0(Native Method)
   at java.net.SocketInputStream.read(...)
   ...
   at javax.swing.text.html.parser.ParserDelegator.read(...)

如果看到 socketRead0 等网络读取 → 外部资源加载阻塞
如果看到 wait() → 锁竞争

打印线程状态

Thread.getAllStackTraces().forEach((thread, stack) -> {
    System.out.println(thread.getName() + " - " + thread.getState());
    for (StackTraceElement e : stack) {
        System.out.println("\t" + e);
    }
});

说明
ReadPending 含义 解析器读取操作尚未完成,线程处于等待状态
主要原因 大 HTML 在 EDT 同步解析、远程资源阻塞、锁竞争
最简修复 Jsoup 在后台提取纯文本后设置
推荐方案 自定义 HTMLEditorKit 禁止外部资源加载
关键原则 不要在 EDT 上执行耗时的 HTML 解析操作

如果你能提供具体的堆栈日志(或代码片段),我可以帮你进一步定位是网络阻塞还是锁死锁导致的挂起。

抱歉,评论功能暂时关闭!