【发布时间】:2022-10-15 01:47:13
【问题描述】:
给定一个理论系统,如果在本地系统中找不到文件,则从 Web 下载文件并假设:
- 下载机制和从/在缓存中检索/放置(本地 文件系统)已经得到照顾。
- 每个 URL 的单线程和单个请求。
我写了一个方法,使用 getFileFromLocalFS() 和 getFileFromWeb() 来实现一个简化的缓存逻辑:
public InputStream getFile(String url) { // #1 InputStream retStream = getFileFromLocalFS(url); if (retStream != null) { return retStream; } else { retStream = getFileFromLocalFS(url); if (retStream == null) { return getFileFromWeb(url); } } return retStream; }然后需要改进这个示意图解决方案以适应同时请求从同一 URL 下载...并将实际的“从 Web”限制为单身的下载(即所有其他请求将从本地文件系统获取)。所以,我同步了整个方法:
public synchronized InputStream getFile(String url) { // #2 InputStream retStream = getFileFromLocalFS(url); if (retStream != null) { return retStream; } else { retStream = getFileFromLocalFS(url); if (retStream == null) { return getFileFromWeb(url); } } return retStream; }这基本上满足了请求,但存在性能问题,因为它会阻止整个方法由另一个线程运行,直到它完成。也就是说,即使可以从本地 FS 获取文件,当该方法由另一个线程运行时,也无法访问
getFileFromLocalFS(url)。我的面试官建议的性能改进是同步
getFileFromLocalFS(url)块:public synchronized InputStream getFile(String url) { // #3 InputStream retStream = getFileFromLocalFS(url); if (retStream != null) { return retStream; } else { synchronized (this) { retStream = getFileFromLocalFS(url); if (retStream == null) { return getFileFromWeb(url); } } } return retStream; }我说“很好,但是要使优化工作,需要删除方法同步”,即:
public InputStream getFile(String url) { // #4 InputStream retStream = getFileFromLocalFS(url); if (retStream != null) { return retStream; } else { synchronized (this) { retStream = getFileFromLocalFS(url); if (retStream == null) { return getFileFromWeb(url); } } } return retStream; }面试官不同意,坚持离开两个都
synchronized到位。哪一个在并发环境中表现更好? #3 还是 #4?为什么?
【问题讨论】:
-
嵌套同步是完全没有必要的,因为您只是锁定在您已经锁定的同一台显示器上。换句话说,#3 不会改进任何东西。从方法声明中删除
synchronized是否正确取决于getFileFromLocalFS的作用,以及它本身是否是线程安全的。换句话说,给定信息,无法说#4 是否正确。 -
#4将是最好的。您不需要同步整个方法
-
getFileFromLocalFS是否还有其他调用者,或者此方法是否仅从getFile调用? -
@Holger 出于这个面试问题的目的(我没有编造,我实际上是在真实的工作面试中被问到的),可以假设
getFileFromLocalFS仅从getFile调用。
标签: java multithreading concurrency synchronized