【问题标题】:Check if file exists on server and return that file content检查服务器上是否存在文件并返回该文件内容
【发布时间】:2018-01-12 10:19:01
【问题描述】:

我想检查该文件是否存在于多线程环境的服务器上,如果存在则直接返回该文件内容或从我的 s3 服务服务器下载。

我的代码是这样的:

final Object lock = new Object();
File file = new File("/file/path");
if (file.exists()) {
    return FileUtils.readFileToByteArray(file);
} else {
    byte[] bytes = this.downloadFileFromRemoteServer();
    if (!file.exists()) {
        synchronized (lock) {
            if(!file.exists()) {
                FileUtils.writeByteArrayToFile(tempFile, bytes);
            }
        }
    }
    tempFile.renameTo(file);
    return bytes;
}

上面的代码类似java双重检查锁定,方法file.exists()的行为是不是类似volatile关键字?和伪代码正确吗?

【问题讨论】:

  • 因为除非文件不存在,否则您的代码不会启动 else 块,看来您有两个无意义的 (!file.exists()) 检查。
  • @Stultuske 这是一个并发环境,其他进程可能正在写入该文件。

标签: java multithreading double-checked-locking


【解决方案1】:

File.exists() 使用文件系统检查文件是否存在,因此它的行为应该像一个 volatile,所以你被覆盖了

虽然有些问题 -

1) 线程一看到文件不存在就开始下载文件,这很费时间,所以很可能其他线程也会来开始下载同一个文件。所以下载部分应该移到锁里面

2) 您正在重命名锁外的临时文件。一个线程可以在不创建/写入临时文件的情况下到达该点。也应该在锁内移动重命名

由于 IO 的开销比锁定要多得多,我认为以上 2 个步骤会有所帮助

【讨论】:

  • 我仍然无法理解 File.exsits() 方法的行为就像一个 volatile。你能告诉我更多吗?
  • 将变量声明为 volatile 可确保其最新值始终对所有线程可见。但是您只需要对存在于 JVM 中(并由其管理)的共享数据执行此操作。当您更改 JVM 外部事物的状态时(例如,在数据库中插入一行或在磁盘上创建一个文件),那么该状态将对任何查看它的线程可见(假设该线程是直接检查状态本身。不是通过其他线程设置的共享变量)
【解决方案2】:

您过于谨慎:由于您正在写入临时文件,因此没有覆盖现有文件的风险,这可能会读取一半写入的文件:您的读取将是一致的。

您的代码要防止的唯一问题是将相同的下载内容写入多个临时文件,与多次下载相比,这并不是什么性能问题,无论如何都会发生。

我会简化你的代码如下:

File file = new File("/file/path");
if (!file.exists()) {
    byte[] bytes = this.downloadFileFromRemoteServer();
    File tempFile = File.createTempFile(...);
    FileUtils.writeByteArrayToFile(tempFile, bytes);
    tempFile.renameTo(file);
}
return FileUtils.readFileToByteArray(file);

【讨论】:

    猜你喜欢
    • 2018-06-02
    • 1970-01-01
    • 2016-02-29
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 2012-10-01
    • 2012-06-13
    相关资源
    最近更新 更多