You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iText8多线程写入同一PDF模板时触发IllegalStateException错误

多线程生成iTextPDF模板文件时的IllegalStateException问题解决

我定义了一个包含多个字段的PDF模板,字段值来自对象属性,单个对象生成PDF正常,但多线程同时为不同对象生成时抛出错误,报错堆栈如下:

Caused by: java.lang.IllegalStateException: Current state = RESET, new state = FLUSHED
    at java.base/java.nio.charset.CharsetEncoder.throwIllegalStateException(CharsetEncoder.java:996)
    at java.base/java.nio.charset.CharsetEncoder.flush(CharsetEncoder.java:679)
    at java.base/java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:808)
    at com.itextpdf.io.font.cmap.CMapCharsetEncoder.encodeUnicodeCodePoint(CMapCharsetEncoder.java:62)
    at com.itextpdf.kernel.font.PdfType0Font.convertToBytes(PdfType0Font.java:386)
    at com.itextpdf.kernel.font.PdfType0Font.writeText(PdfType0Font.java:414)
    at com.itextpdf.kernel.pdf.canvas.PdfCanvas.showText(PdfCanvas.java:826)
    at com.itextpdf.kernel.pdf.canvas.PdfCanvas.showText(PdfCanvas.java:708)
    at com.itextpdf.layout.renderer.TextRenderer.draw(TextRenderer.java:977)
    at com.itextpdf.layout.renderer.AbstractRenderer.drawChildren(AbstractRenderer.java:1036)
    at com.itextpdf.layout.renderer.AbstractRenderer.draw(AbstractRenderer.java:475)
    at com.itextpdf.layout.renderer.ParagraphRenderer.drawChildren(ParagraphRenderer.java:584)
    at com.itextpdf.layout.renderer.BlockRenderer.draw(BlockRenderer.java:564)
    at com.itextpdf.forms.form.renderer.AbstractFormFieldRenderer.drawChildren(AbstractFormFieldRenderer.java:199)
    at com.itextpdf.layout.renderer.BlockRenderer.draw(BlockRenderer.java:564)
    at com.itextpdf.forms.form.renderer.AbstractFormFieldRenderer.draw(AbstractFormFieldRenderer.java:183)
    at com.itextpdf.layout.renderer.CanvasRenderer.flushSingleRenderer(CanvasRenderer.java:108)
    at com.itextpdf.layout.renderer.RootRenderer.processRenderer(RootRenderer.java:370)
    at com.itextpdf.layout.renderer.RootRenderer.shrinkCurrentAreaAndProcessRenderer(RootRenderer.java:321)
    at com.itextpdf.layout.renderer.RootRenderer.addChild(RootRenderer.java:223)
    at com.itextpdf.layout.renderer.CanvasRenderer.addChild(CanvasRenderer.java:72)
    at com.itextpdf.layout.RootElement.createAndAddRendererSubTree(RootElement.java:346)
    at com.itextpdf.layout.RootElement.addElement(RootElement.java:355)
    at com.itextpdf.layout.RootElement.add(RootElement.java:84)
    at com.itextpdf.forms.fields.PdfFormAnnotation.drawTextFormFieldAndSaveAppearance(PdfFormAnnotation.java:912)
    at com.itextpdf.forms.fields.PdfFormAnnotation.regenerateWidget(PdfFormAnnotation.java:1072)
    at com.itextpdf.forms.fields.PdfFormField.regenerateField(PdfFormField.java:1097)
    at com.itextpdf.forms.fields.PdfFormField.setFieldValue(PdfFormField.java:1426)
    at com.itextpdf.forms.fields.PdfFormField.setValue(PdfFormField.java:368)
    at com.itextpdf.forms.fields.PdfFormField.setValue(PdfFormField.java:356)

问题原因

这个错误的核心是iText的字体对象(如PdfType0Font)并非线程安全。多线程场景下,若多个任务共用同一个字体实例,底层的CharsetEncoder状态会被并发修改,导致状态冲突(RESET与FLUSHED状态不一致),最终抛出IllegalStateException。通常是因为模板初始化时加载的字体资源被全局共享,未做线程隔离处理。

解决方案

  • 每个线程独立加载字体实例:不在全局缓存或单例中存储字体对象,而是在每个PDF生成任务内部单独加载字体,确保每个线程拥有专属的字体实例。
    // 每个生成任务内单独初始化字体
    PdfFont font = PdfFontFactory.createFont("font/path/your-font.ttf", PdfEncodings.IDENTITY_H);
    
  • 对共享资源加线程锁:若必须复用模板或字体资源,在访问这些资源的代码块上添加synchronized锁,保证同一时间只有一个线程执行相关操作。
    // 定义全局锁对象
    private static final Object TEMPLATE_LOCK = new Object();
    
    // 生成PDF时加锁
    synchronized (TEMPLATE_LOCK) {
        // 填充字段、生成PDF的逻辑
        pdfFormField.setValue(fieldValue);
    }
    
  • 使用ThreadLocal存储资源:将字体或模板实例存入ThreadLocal,每个线程获取自己的资源副本,彻底避免并发冲突。
    private static final ThreadLocal<PdfFont> FONT_THREAD_LOCAL = ThreadLocal.withInitial(() -> {
        try {
            return PdfFontFactory.createFont("font/path/your-font.ttf", PdfEncodings.IDENTITY_H);
        } catch (IOException | PdfException e) {
            throw new RuntimeException("初始化字体失败", e);
        }
    });
    
    // 在任务中获取线程专属字体
    PdfFont font = FONT_THREAD_LOCAL.get();
    

内容的提问来源于stack exchange,提问作者Lonely

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 09:13:11