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

IOUtils.closeQuietly()是否线程安全?如何解决其引发的NPE问题?

解决IOUtils.closeQuietly调用DeflaterInputStream时的NPE问题

问题根源

从栈追踪和DeflaterInputStream的close代码来看,多线程重复调用close引发了竞态条件:

  • 线程A进入if (in != null)分支后,在finally块中将in置为null;
  • 线程B此时已经通过了if (in != null)的检查,后续执行in.close()或def.end()时,由于in已被线程A置为null,直接触发NullPointerException。

无需synchronized的解决办法

1. 业务层控制close只执行一次

用volatile标记位保证多线程可见性,确保close逻辑仅被执行一次:

private volatile boolean isClosed = false;
private DeflaterInputStream deflaterStream;

// 关闭方法
public void safeCloseStream() {
    if (!isClosed) {
        isClosed = true;
        IOUtils.closeQuietly(deflaterStream);
    }
}

volatile关键字能让所有线程实时感知到isClosed的状态变化,避免多个线程同时进入关闭流程。

2. 用原子类实现原子性关闭检查

借助AtomicBoolean的原子操作,确保只有一个线程能执行关闭逻辑:

private AtomicBoolean closedFlag = new AtomicBoolean(false);
private DeflaterInputStream deflaterStream;

public void safeCloseStream() {
    // 仅当flag为false时才执行关闭,并原子性置为true
    if (closedFlag.compareAndSet(false, true)) {
        try {
            if (deflaterStream != null) {
                deflaterStream.close();
            }
        } catch (IOException ignored) {
            // 静默处理异常,对齐IOUtils.closeQuietly的行为
        }
    }
}

这种方式比synchronized更轻量,原子操作的性能开销远低于锁竞争。

3. 替换为线程安全的流包装类

如果业务场景允许,可以用SynchronizedInputStream包装DeflaterInputStream,让所有流操作(包括close)都自带线程安全:

DeflaterInputStream deflaterStream = new DeflaterInputStream(originalStream);
InputStream safeStream = new SynchronizedInputStream(deflaterStream);
// 后续操作safeStream,关闭时直接调用IOUtils.closeQuietly(safeStream)

注意:这种方式会给所有流操作加锁,性能开销略高于前两种,但实现简单。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 13:53:22