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

并发环境下,getFile方法的#3与#4实现哪个性能更优?原因是什么?

并发场景下缓存获取方法的性能对比:#3 vs #4

背景与代码回顾

我们有一个文件缓存系统:本地有文件则从本地读取,否则从Web下载并缓存(假设下载和缓存的读写逻辑已实现,单URL对应单请求)。

初始单线程版本(#1)

public InputStream getFile(String url) {
    InputStream retStream = getFileFromLocalFS(url);
    if (retStream != null) {
        return retStream;           
    }
    else {
        retStream = getFileFromLocalFS(url);
        if (retStream == null) {
            return getFileFromWeb(url);
        }
    }
    return retStream;
}

全方法同步版本(#2)

为支持并发且避免重复下载,给整个方法加了synchronized,但导致所有请求串行,即使本地有文件也无法并行读取:

public synchronized InputStream getFile(String url) {
    InputStream retStream = getFileFromLocalFS(url);
    if (retStream != null) {
        return retStream;           
    }
    else {
        retStream = getFileFromLocalFS(url);
        if (retStream == null) {
            return getFileFromWeb(url);
        }
    }
    return retStream;
}

面试官提出的双重同步版本(#3)

试图通过局部同步块优化,但保留了方法级同步:

public synchronized InputStream getFile(String url) {
    InputStream retStream = getFileFromLocalFS(url);
    if (retStream != null) {
        return retStream;           
    }
    else {
        synchronized (this) { 
            retStream = getFileFromLocalFS(url);
            if (retStream == null) {
                return getFileFromWeb(url);
            }
        }
    }
    return retStream;
}

移除方法级同步的版本(#4)

去掉方法级同步,仅在本地未命中时进入同步块:

public InputStream getFile(String url) {
    InputStream retStream = getFileFromLocalFS(url);
    if (retStream != null) {
        return retStream;           
    }
    else {
        synchronized (this) { 
            retStream = getFileFromLocalFS(url);
            if (retStream == null) {
                return getFileFromWeb(url);
            }
        }
    }
    return retStream;
}

性能对比分析

结论:#4的性能远优于#3

原因如下:

  1. #3的方法级同步完全抵消了局部同步块的优化
    方法级synchronized等价于在整个方法体外包裹synchronized(this),所以#3的所有请求都必须先获取this锁才能执行任何逻辑——不管目标文件是否在本地缓存,所有线程都得串行执行,和#2的性能没有区别。内部的嵌套同步块只是同一线程的重入锁,没有任何实际优化作用,完全是多余的。

  2. #4真正实现了锁细化,适配缓存的高频/低频路径

    • 高频路径(本地有文件):无锁执行getFileFromLocalFS,所有线程可以并行读取本地缓存,这是缓存场景下的主流情况,能极大提升并发吞吐量。
    • 低频路径(本地无文件):仅这部分请求进入同步块做二次检查,确保同一URL只会触发一次Web下载,即使串行也不会影响整体性能。

内容的提问来源于stack exchange,提问作者Bill The Ape

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 17:10:33