gpt4 book ai didi

java - 为什么 File.exists() 在多线程环境中表现异常?

转载 作者:行者123 更新时间:2023-12-03 23:11:01 56 4
gpt4 key购买 nike

我有一个在 java JDK 1.7 下运行的批处理。它在带有 RHEL、2.6.18-308.el5 #1 SMP 的系统上运行。

此过程从数据库中获取元数据对象列表。从该元数据中,它提取文件的路径。该文件可能实际存在也可能不存在。

该进程使用 ExecutorService (Executors.newFixedThreadPool()) 来启动多个线程。每个线程运行一个 Callable,如果该输入文件存在(并记录结果),则启动一个读取该文件并写入另一个文件的进程,如果该文件不存在则不执行任何操作(记录该结果除外)。

我发现这种行为是不确定的。尽管每个文件的实际存在自始至终都是不变的,但运行此过程并不能给出一致的结果。它通常会给出正确的结果,但偶尔会发现一些确实存在的文件不存在。如果我再次运行相同的进程,它会发现它之前说的文件不存在。

为什么会发生这种情况,是否有另一种更可靠的方法?在其他线程尝试读取目录时在多线程进程中写入文件是错误的吗?较小的线程池会有所帮助(目前为 30 个)吗?

更新:
以下是此场景中工作线程调用的 unix 进程的实际代码:

public int convertOutputFile(String inputFile, String outputFile)
throws IOException
{
List<String> args = new LinkedList<String>();
args.add("sox");
args.add(inputFile);
args.add(outputFile);
args.addAll(2, this.outputArguments);
args.addAll(1, this.inputArguments);
long pStart = System.currentTimeMillis();
int status = -1;
Process soxProcess = new ProcessBuilder(args).start();

try {
// if we don't wait for the process to complete, player won't
// find the converted file.
status = soxProcess.waitFor();
if (status == 0) {
logger.debug(String.format("SoX conversion process took %d ms.",
System.currentTimeMillis() - pStart));
} else {
logger.error("SoX conversion process returned an error status of " + status);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return status;
}

更新#2:

我尝试过从 java.io.File.exists() 切换到 java.nio.Files.exists() 的实验,这似乎提供了更高的可靠性。我还没有看到多次尝试的失败情况,和以前一样,大约有 10% 的时间发生。所以我想我想知道 nio 版本在处理底层文件系统的方式上是否更健壮。 这一发现后来被证明是错误的。 nio 在这里没有帮助。

更新#3:
经过进一步审查,我仍然发现发生相同的故障情况。所以切换到nio并不是万能的。通过将执行程序服务的线程池大小减少到 1,我获得了更好的结果。这似乎更可靠,并且没有机会一个线程读取目录,而另一个线程正在启​​动一个写入相同的进程目录。

我尚未调查的另一种可能性是,将输出文件放在与输入文件不同的目录中是否会更好。我将它们放在同一个目录中是因为它更容易编码,但这可能会造成混淆,因为输出文件的创建会影响与输入目录扫描相同的目录。

更新 #4:
重新编码以便将输出文件写入与输入文件(正在检查其存在)不同的目录并没有特别帮助。 唯一有帮助的变化是 ExecutorService 线程池大小为 1,换句话说,不是多线程这个操作。

最佳答案

我已将@Olivier 的答案标记为“the”答案,但我在这里提供我自己的答案,以总结我的实验结果。我将其称为比其他任何人都更接近真相的“答案”,尽管他对文件句柄的猜测似乎并不明显正确,尽管我也无法反驳它。真正正确的是他的简单陈述“您的应用程序可能是适当的多线程,无论何时访问文件系统,它都有限制。”这与我的发现一致。如果有人能进一步阐明,我可能会改变这一点。

  • 这是我的代码中的错误吗?

  • 高度怀疑。在相同的文件列表上重复运行相同的过程会随机显示一些文件显示为不存在,而实际上它们确实存在。再次运行该过程,发现这些相同的文件存在。这些文件的存在在此期间发生变化的可能性为零。
  • 是否使用 java.nio.Files.exists()而不是 java.io.File.exists()帮助?

  • 不会。文件系统的底层接口(interface)似乎没有什么不同。 nio 在这方面的改进似乎仅限于 nio 中对链接的处理,这不是这里的问题。但我不能肯定地说,因为这是 native 代码。
  • 是否将输入和输出文件放在不同的目录中,以便我的存在检查不会读取输出文件被写入的同一目录,有帮助吗?

  • 不会。 上似乎不是两个同时点击。目录 这会导致问题,多达两个同时点击 文件系统 .
  • 减少池中的线程数有帮助吗?

  • 只有将其减少到 1 才能使其可靠,换句话说,只有完全取消多线程方法才有帮助。这个操作似乎不是 100% 可靠的,至少在这个操作系统和 JDK 中不是,多线程的。

    如果要重新设计 sox 以便在输入文件上为 File Not Found 提供不同的错误代码,这可能会使上述@EJP 的答案变得可行。

    关于java - 为什么 File.exists() 在多线程环境中表现异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34644187/

    56 4 0
    文章推荐: java - 将 List 转换为 List>