使用PDFBox 2.0.1提取PDF文本时CPU占用100%问题咨询
嘿,我来帮你搞定这个PDFBox多线程解析时CPU跑满的问题!结合你贴的代码,咱们从几个方向入手解决:
一、合理控制并发线程数,避免CPU资源被过度抢占
你现在直接循环创建5个线程,如果你的CPU核心数不多,很容易被这些线程占满所有核心。建议用线程池来调度,根据CPU核心数设置合理的并发数,比如:
// 获取当前机器的CPU核心数,以此为基准设置线程池参数 int corePoolSize = Runtime.getRuntime().availableProcessors(); ExecutorService executor = new ThreadPoolExecutor( corePoolSize, corePoolSize * 2, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>() ); for (int i = 0; i < 5; i++) { executor.submit(() -> { InputStream in = new ByteArrayInputStream(fileContent); PDDocument document = null; PDFTextStripper stripper; String content; try { document = PDDocument.load(in); stripper = new PDFTextStripper(); content = stripper.getText(document).trim(); System.out.println(content); } catch (IOException e) { e.printStackTrace(); } finally { try { if (document != null) { document.close(); } if (in != null) { in.close(); } } catch (IOException e) { e.printStackTrace(); } } }); } executor.shutdown();
线程池会自动帮你管理线程的创建和销毁,避免无限制的线程抢占CPU资源。
二、复用PDFTextStripper实例,减少重复初始化开销
PDFTextStripper的初始化过程是有不小开销的,你现在每个线程都new一个新实例,会额外消耗CPU资源。虽然PDFTextStripper是线程不安全的,但我们可以用ThreadLocal为每个线程维护一个专属实例,避免重复创建:
// 用ThreadLocal存储每个线程的PDFTextStripper实例,初始化一次复用 private static final ThreadLocal<PDFTextStripper> STRIPPER_THREAD_LOCAL = ThreadLocal.withInitial(() -> { try { return new PDFTextStripper(); } catch (IOException e) { throw new RuntimeException("Failed to initialize PDFTextStripper", e); } }); // 在线程逻辑中直接获取实例 stripper = STRIPPER_THREAD_LOCAL.get(); content = stripper.getText(document).trim();
这样每个线程只会初始化一次PDFTextStripper,能有效降低CPU的额外消耗。
三、升级PDFBox到最新稳定版本
你使用的2.0.1版本是2017年的老版本,后续的2.x版本修复了大量性能问题和多线程相关的bug,比如字体加载优化、锁竞争修复等。升级到最新的2.x稳定版(比如2.0.32或更高),很多时候就能直接解决CPU占用过高的问题。
四、优化PDF加载逻辑
如果fileContent是同一个PDF的字节数组,每个线程都重新加载整个文档会重复消耗资源。你可以尝试用PDDocument.loadNonSeq替代PDDocument.load,在某些复杂PDF场景下,这个方法的加载性能更好:
document = PDDocument.loadNonSeq(in, null);
另外,如果你的PDF包含大量复杂字体或矢量图形,这类PDF本身解析就会消耗较多CPU,必要时可以先对PDF做预处理(比如合并重复字体、压缩内容)。
五、排查潜在的代码问题
检查你代码中System.out.println(...后面是否有未完成的逻辑,比如无限循环?如果输出的内容量极大,也会导致IO线程阻塞,间接推高CPU占用。同时要确保流和PDDocument都被正确关闭,避免资源泄漏引发的后续问题。
内容的提问来源于stack exchange,提问作者villa

