检查服务器上是否存在文件以及 return 该文件内容

Check if file exists on server and return that file content

我想检查文件是否存在于多线程环境的服务器上,如果存在return该文件内容直接或从我的 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关键字?伪代码正确吗?

您过于谨慎了:因为您正在写入临时文件,所以不存在覆盖现有文件的风险,这可能会读取写入一半的文件:您的读取将是一致的。

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

我会将您的代码简化如下:

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);

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

虽然有些问题 -

1) 一旦一个线程发现该文件不存在,它就会开始下载该文件,这很耗时,因此很可能其他线程也会来并开始下载同一个文件。所以下载部分要移到lock里面

2) 您正在重命名锁外的临时文件。线程可能会在没有 creating/writing-to 临时文件的情况下达到这一点。也应该将重命名移动到锁内

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