我想检查多线程环境中的服务器上是否存在该文件,如果存在,则从我的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关键字?和伪代码正确吗?
答案 0 :(得分:2)
File.exists()用文件系统检查文件是否存在,所以它的行为应该像volatile一样,所以你就被覆盖了
但有些问题 -
1)一旦线程看到文件不存在,它就会开始下载文件,这很费时间,因此很可能其他线程也会开始下载同一个文件。所以下载部分应该在锁内移动
2)您在锁外重命名临时文件。线程可以在不创建/写入临时文件的情况下到达该点。应该在锁内移动重命名
由于IO比锁定有更多的开销,我认为上述两个步骤将是有益的
答案 1 :(得分:0)
你过于谨慎:因为你正在写一个临时文件,所以不存在覆盖现有文件的风险,这有可能读取半文件:你的读取将是一致的。
您的代码正在防范的唯一问题是将相同的下载内容写入多个临时文件,与多次下载相比,这不会产生太大的性能问题,无论如何都会发生。
我会按如下方式简化您的代码:
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);