本文目录导读:

看到你提到的这个错误信息 JEditorPaneHTMLEditorKitParserMethodIllegalBlocking(非法阻塞),这通常与 Java Swing 中的 JEditorPane 和 HTMLEditorKit 的 HTML 解析器有关。
这个错误的核心原因是:在 Swing 的事件调度线程(EDT,Event Dispatch Thread)上执行了耗时的 HTML 解析或网络请求,导致线程被阻塞,违反了 Swing 的单线程规则。
详细解释
什么是非法阻塞(Illegal Blocking)?
- EDT(事件调度线程):Swing 的所有 UI 更新和事件处理都应该在这个线程上完成。
- 非法阻塞:如果在 EDT 上执行了阻塞操作(如网络请求、复杂文件解析、长时间计算),会导致 UI 冻结(无响应)。
- 当你使用
JEditorPane加载包含图片或外部资源的 HTML 时,解析器可能会尝试同步加载这些资源,如果这个操作发生在 EDT 上,就会抛出IllegalBlocking异常(或类似的阻塞警告/异常)。
常见触发场景
-
直接设置 HTML 内容时包含远程图片/资源:
// 错误示例:直接在 EDT 上加载含网络图片的 HTML JEditorPane editor = new JEditorPane(); editor.setContentType("text/html"); editor.setText("<html><img src='http://example.com/image.jpg'></html>"); // 阻塞! -
使用
setPage()方法加载远程 HTML 页面:editor.setPage(new URL("http://example.com/page.html")); // 阻塞! -
自定义 HTMLEditorKit 解析器,在解析回调中执行了耗时操作。
解决方案
方案 1:在后台线程加载 HTML 内容(推荐)
使用 SwingWorker 或单独线程来下载 HTML 内容,完成后通过 SwingUtilities.invokeLater() 更新 UI。
SwingWorker<Void, Void> worker = new SwingWorker<>() {
@Override
protected Void doInBackground() throws Exception {
// 1. 在后台线程下载 HTML 内容或图片
String htmlContent = downloadHtmlFromNetwork();
// 或者使用 URLConnection 手动下载资源
return null;
}
@Override
protected void done() {
// 2. 回到 EDT 更新 UI
try {
String html = get(); // 或直接从 doInBackground 传递
editorPane.setText(html);
} catch (Exception e) {
e.printStackTrace();
}
}
};
worker.execute();
方案 2:禁用外部资源加载(如果不需要)
HTML 中不需要显示外部图片,可以禁止 HTMLEditorKit 自动加载图片。
HTMLEditorKit kit = new HTMLEditorKit() {
@Override
public ViewFactory getViewFactory() {
return new HTMLEditorKit.HTMLFactory() {
@Override
public View create(Element elem) {
View view = super.create(elem);
if (view instanceof ImageView) {
// 返回一个空视图或自定义视图,避免加载图片
return new NullImageView(elem);
}
return view;
}
};
}
};
editorPane.setEditorKit(kit);
方案 3:自定义 HTMLEditorKit 的图片加载逻辑
通过覆盖 ImageView 的 getImage() 方法,使用异步加载。
HTMLEditorKit kit = new HTMLEditorKit() {
@Override
public ViewFactory getViewFactory() {
return new HTMLEditorKit.HTMLFactory() {
@Override
public View create(Element elem) {
if (elem.getName().equals("img")) {
return new AsyncImageView(elem);
}
return super.create(elem);
}
};
}
};
方案 4:使用 Flyweight 模式或缓存(高级)
对于复杂场景,可以构建一个资源缓存,在 EDT 外预加载所有资源,然后在 EDT 上设置包含缓存资源路径的 HTML。
诊断步骤
- 检查堆栈跟踪:异常信息中会明确显示哪些代码在 EDT 上执行了阻塞操作。
- 添加日志:
System.out.println("Current thread: " + Thread.currentThread().getName()); // 如果是 EventQueue 或 AWT-EventQueue,说明在 EDT 上 - 简化测试:移除 HTML 中的外部资源引用,只保留纯文本内容,看是否还会出现该异常。
注意事项
- 不要调用
Thread.sleep(),Thread.sleep()或其他阻塞方法(InputStream.read(),URLConnection.connect())在 EDT 上。 - 使用
javax.swing.Timer代替Thread.sleep()进行定时任务。 - 考虑使用
java.util.concurrent.CompletableFuture进行更优雅的异步编程。
如果你能提供具体的代码片段(尤其是设置 JEditorPane 内容的部分),我可以给出更精确的修改建议。