为什么 File.exists() 在多线程环境中表现不稳定?

2024-02-09

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

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

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

我发现这种行为是不确定的。尽管每个文件的实际存在始终是恒定的,但运行此过程不会给出一致的结果。它通常会给出正确的结果,但有时会发现一些确实存在的文件并不存在。如果我再次运行相同的进程,它将找到之前所说的不存在的文件。

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

UPDATE:以下是此场景中工作线程调用的 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”答案,但我在这里提供自己的答案,以总结我的实验结果。我称其为比其他人更接近事实的“答案”,尽管他对文件句柄的猜测似乎并不明显正确,尽管我也无法反驳它。听起来真实的是他的简单陈述”您的应用程序可能是适当的多线程,每当您访问文件系统时,它都有限制。“这与我的发现是一致的。如果有人能提供任何进一步的线索,我可能会改变这一点。

  1. 这是我的代码中的错误吗?

非常值得怀疑。对同一文件列表重复运行相同的进程会随机显示一些文件显示为不存在,而实际上它们确实存在。再次运行该进程,发现这些相同的文件存在。这些文件的存在在此期间发生改变的可能性为零。

  1. 是否使用java.nio.Files.exists()而不是java.io.File.exists() help?

不会。文件系统的底层接口似乎没有什么不同。 nio 在这方面的改进似乎仅限于 nio 中链接的处理,这不是这里的问题。但我不能肯定地说,因为这是本机代码。

  1. 将输入和输出文件放在不同的目录中,以便我的存在检查不会读取输出文件写入的同一目录,是否有帮助?

不。这似乎不是两次同时点击目录导致问题的原因是,两次同时点击文件系统.

  1. 减少池中的线程数量有帮助吗?

只有将其减少到 1 才能使其可靠,换句话说,只有完全消除多线程方法才有帮助。此操作似乎不是 100% 可靠,至少对于这个操作系统和 JDK(多线程)来说是这样。

如果 sox 被重新设计,以便为输入文件上的“找不到文件”提供不同的错误代码,这可能会使上面 @EJP 的答案变得可行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 File.exists() 在多线程环境中表现不稳定? 的相关文章

  • Hibernate OneToMany 关系是 PersistentBag 而不是 List

    我正在 javafx 中开发一个应用程序 它通过 RMI 与 EAR 连接 该 EAR 连接到 SQLServer DB 并使用 hibernate 映射 POJOS 这些 POJOS 包含双向 OneToMany 和 ManyToOne
  • V8 如何管理它的堆?

    我知道V8的垃圾收集在工作时 会从GC的root开始追踪 这样无法到达的对象就会被标记然后被清除 我的问题是GC是如何遍历那些对象的 必须有一个数据结构来存储所有可达或不可达的对象 位图 链接表 顺便说一句 JVM 也做同样的事情吗 艾伦秀
  • 判断线程是否已经启动

    如何判断Python线程是否已经启动 有一个方法is alive 但这是真的before and while一个线程正在运行 你可以看看ident领域的Thread实例 这Python 2 7 线程文档 http docs python o
  • Maven + Cobertura:无法找到[您的班级]。你指定了源目录吗?

    我有 MyMath 类 有两个简单的方法 multi 和 add 和测试类只会测试多种方法 public class MainTest Test public void testMultiply MyMath tester new MyMa
  • 方法不必要地被调用?

    我有一个 BaseActivity 它可以通过其他所有活动进行扩展 问题是 每当用户离开 暂停 活动时 我都会将音乐静音 我也不再接听电话 问题是 onPause每当用户在活动之间切换时就会被调用 这意味着应用程序不必要地静音和停止tele
  • 删除 servlet 中的 cookie 时出现问题

    我尝试使用以下代码删除 servlet 中的 cookie Cookie minIdCookie null for Cookie c req getCookies if c getName equals iPlanetDirectoryPr
  • 业务代表与服务定位器

    Business Delegate 和 Service Locator 之间有什么区别 两者都负责封装查找和创建机制 如果 Business Delegate 使用 Service Locator 来隐藏查找和创建机制 那么 Busines
  • 如何模拟一个方面

    我目前正在使用aspectj 开发一些监控工具 因为这个工具应该是技术独立的 尽可能 所以我没有使用 Spring 进行注入 但我希望我的方面能够经过单元测试 方面示例 Aspect public class ClassLoadAspect
  • Java 的 QP 求解器 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在 Spring 中设置 WS https 调用超时 (HttpsUrlConnectionMessageSender)

    我正在尝试为 WS 调用设置超时 我延长了WebServiceGatewaySupport并尝试将发送者超时设置为如下 public Object marshalSendAndReceive Object requestPayload We
  • 您能让 Tomcat 6 stdout.log 文件表现得像 log4j DailyRollingFileAppender 吗?

    我们使用的是 Tomcat 6 的 Windows 安装 默认情况下 我们应用程序的 log4j 输出将转到 catalina base logs stdout log 文件 该日志文件仅在我们重新启动 Tomcat 时滚动 并且文件名始终
  • java JFileChooser 文件大小过滤器

    我知道我可以按文件类型进行过滤 但是可以按文件大小进行过滤吗 例如 JFileChooser 仅显示 3 MB 以内的图片 简短的回答应该是 你尝试过什么 长答案是肯定的 JFileChooser fc new JFileChooser f
  • 如何使用 Java 原生接口从 Java 调用 Go 函数?

    可以通过以下方式调用 C 方法JNA https en wikipedia org wiki Java Native AccessJava 中的接口 如何使用 Go 实现相同的功能 package main import fmt impor
  • Java G1 GC 处理引用对象运行缓慢

    我已经在 J ava 上运行了计数器 它24小时工作 每秒点击通过100次左右 白天 GC 处理时间从 20 60 毫秒缓慢上升到 10000 60000 毫秒 然后下降到 20 60 毫秒 这种模式不时地重复 从 GC 日志中我发现 GC
  • Java String.format 向整数添加空格

    我有一小段代码 我不明白输出 此输出向我的字符串格式文本添加空格 我做错了什么吗 public class HelloWorld public static void main String args int a1 540 int a2 4
  • 当容器大小更改时,JTable 仅调整选定列的大小

    对于面板内的 JTable 如果面板变大 我如何将额外的空间仅分配给某些列 在我的例子中 分配给最后一列 尽管提供 第 3 4 列和8 将获得额外的空间 我想允许用户手动更改所有列的列大小 我尝试了 table setAutoResizeM
  • 嵌入式 tomcat 7 servlet 3.0 注释不起作用

    我有一个精简的测试项目 其中包含 Servlet 版本 3 0 用注释声明 如下所示 WebServlet test public class TestServlet extends HttpServlet private static f
  • 字节码和位码有什么区别[重复]

    这个问题在这里已经有答案了 可能的重复 LLVM 和 java 字节码有什么区别 https stackoverflow com questions 454720 what are the differences between llvm
  • 存储过程将多个表返回到 spring jdbc 模板

    我正在使用 JdbcTemplate 从 Spring DAO 类调用存储过程 我的问题是 存储过程返回多个表 有没有办法使用 Spring JdbcTemplate 访问多个表 如果我使用jdbcTemplate queryForList
  • 将隐藏(生物识别)数据附加到 pdf 上的数字签名

    我想知道是否可以使用 iText 我用于签名 或 Java 中的其他工具在 pdf 上添加生物识别数据 我会更好地解释一下 在手写板上签名时 我会收集签名信息 例如笔压 签名速度等 我想将这些信息 java中的变量 与pdf上的签名一起存储

随机推荐