【问题标题】:Waiting for File Lock to Be Released等待文件锁被释放
【发布时间】:2016-03-24 22:39:26
【问题描述】:

有一些与此类似的 Java 问题,但没有一个接受我能找到的答案,而且我的情况更具体一些。我有一个程序,在将文件输入目录时一次处理一个文件。有时,这些文件可能会在我的程序可见后被程序删除几秒钟后仍处于锁定状态。我无法控制那个程序。在我的程序中,当我的程序尝试读取文件时,如果文件正在使用中,我已经有错误处理来恢复它。它会导致文件被完全跳过。我想要实现的是一个重试方案,以查看文件是否在几秒钟后解锁。在另一个问题中,我发现了使用FileUtils.touch() 的建议。这很方便,因为我已经在我的项目中使用了 FileUtils。根据 javadoc,FileUtils.touch() 如果文件正被另一个进程使用,则抛出 IOException。听起来很棒。但是,我提到的答案中的一个 cmets 在没有任何解释的情况下警告了比赛条件。这是我正在考虑实施的代码:

// Implementing Sason's suggestion
int retries = 0;
while (retries < MAX_RETRIES) {
    try {
        processFile(file);
    } catch (IOException ioe) {
        // Assumes this is a file in use exception... bad thing?
        log.warn("File is in use.  Waiting 1 second to retry.");
        retries++;
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ie) {
            log.warn("Thread interrupted while waiting for file lock to clear.");
            break;
        }
    }
}

我意识到文件可能在 FileUtils.touch() 和 processFile() 方法调用之间再次被锁定(我认为这是在我找到的未接受答案中警告的竞争条件),但这很好。 processFile() 方法将像当前一样处理锁定错误。需要明确的是,在这种情况下,文件被另一个进程打开但不能被锁定是完全可以的。

此外,虽然有时文件确实会在一两秒后解锁,但在某些情况下,删除文件的程序会无限期地保持锁定。我还需要避免无限地尝试重新处理同一个文件,并且能够在重试用尽后无法处理文件时通知发件人。

那么我在这里遗漏了什么吗?有没有更好/更安全的方法来做到这一点?

【问题讨论】:

  • 这听起来不像touch() 是测试文件是否打开的可靠方法。它可能在具有特定进程的特定系统上运行,这很好,但是如果您在其他地方运行代码或更改编写器,则需要重新测试以确保它仍然有效。正确的做法是使用FileLock,但这需要编写程序使用底层文件系统锁定机制。
  • 我的问题应该更清楚。如果文件在另一个没有锁定文件的进程中打开(例如,NotePad++),则可以。它只是无法锁定,因为processFile() 将尝试锁定文件。我确实明白你关于FileLock 的观点,但你说得对,它需要进行相当多的重构。我确实认为touch() 可以跨平台工作,但需要注意的是另一个程序可能会打开文件但未锁定。

标签: java io fileutils


【解决方案1】:

我会使用 SchedueledExecutorService 来提交尝试处理文件的延迟工作。如果处理失败,请反复发布作品,直到成功为止。

这里需要 FileUtils.touch 吗?为什么不尝试读取文件,如果失败重试?

thread.sleep 有点丑。如果处理多个文件,每个文件都必须使用自己的线程,直到完成。 ScheduledExecutorService 会更有效率。

【讨论】:

  • 我同意。比赛是因为检查和动作之间没有原子性。如果由于无法获取锁而导致操作失败,则没有问题。稍后再试。
  • 这是一个有趣的想法,我曾考虑过但最初拒绝了,因为有时文件会无限期地保持锁定状态,并且程序会卡在无法处理的文件上循环。在错误处理中,向发件人提供无法处理文件的通知,并将文件添加到忽略列表中。在一天结束时,无法处理的文件列表将发送给发件人。我真的不想改变这种行为,我只想让文件在进入未处理列表之前等待几秒钟。
  • 另外,我同意 Thread.sleep() 有点难看,但文件确实需要同步处理,所以如果它阻止下一个要处理的文件也没关系。我几乎希望我不必按顺序处理文件(尽可能接近到达顺序)。这实际上会大大简化事情,因为我可以完全按照您所说的去做,并且在一定次数的重试后让可运行文件本身过期。我什至可以改用 Future
  • 嗯,执行器不会阻止您保持重试计数并停止重试。另一件事是您忽略了中断的异常并继续循环。您损害了应用程序及时关闭的能力。
  • 您对 InterruptedException 的看法是正确的,感谢您指出这一点。我想我在 Executor 上遗漏了一些东西。评论太长了,但是如果我一次处理 10 个文件并且第一个文件被锁定,则可运行文件需要在内部重试该文件或在内部跟踪该文件,以便下次执行时知道它是尝试第二次,第三次等时间。这似乎会更令人困惑。这真的比我所做的更好吗?我一定是错过了什么。
猜你喜欢
  • 2010-11-27
  • 2019-08-24
  • 2010-10-15
  • 2015-01-25
  • 1970-01-01
  • 2019-03-25
  • 2021-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多