我编写了一个小方法,用于告诉我该应用程序的另一个实例是否已在运行。我知道有很多方法可以找出另一个实例是否正在运行,但我选择了这个。我正在创建一个空文件,并在应用程序实例的持续时间内保持锁定状态。如果另一个实例正在运行,则tryLock()方法应返回null:
private static boolean alreadyRunning() throws IOException {
FileChannel fc = FileChannel.open(MYLOCKFILE,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.DELETE_ON_CLOSE);
return fc.tryLock() == null;
}
(对于临时目录中的文件,MYLOCKFILE是Path
。)
在Windows 7 Professional 64位上测试时,我发现第一个实例和第二个尝试实例的工作正常。但是,在第二个实例退出后(仅运行第一个实例),当运行第三个实例时,tryLock()调用将抛出java.nio.file.AccessDeniedException
而不是返回null。你能解释一下这种行为吗?如果这被认为是正常行为,我如何区分具有文件锁定的现有实例和真实的“拒绝访问”情况,例如将TEMP目录设置为只读的白痴?
答案 0 :(得分:2)
我做了一个测试项目并测试了代码唯一的问题,因为在代码中使用了java.nio.file.AccessDeniedException
抛出的StandardOpenOption.DELETE_ON_CLOSE
选项。
我删除了该选项,现在工作正常
FileChannel fc = FileChannel.open(MYLOCKFILE, StandardOpenOption.CREATE,
StandardOpenOption.WRITE);
我可以认为因为引发java.nio.file.AccessDeniedException
而导致的是,只要第二个实例终止选项StandardOpenOption.DELETE_ON_CLOSE
[More explaination],就会尝试在JVM退出时删除该文件并失败可能已在内核或操作系统中注册了一个事件,以便在可能的情况下删除该文件。因此,如果任何其他进程尝试访问,在删除之前创建或写入相同的文件,则会抛出java.nio.file.AccessDeniedException
,因为该文件的删除操作已经挂起。
修改强>
根据您的新评论,您可以在检查try finally
代码后的alreadyRunning()
块中添加以下代码。
摘录示例:
if(!alreadyRunning())
{
try
{
// YOUR CODE THAT RUNS
while(true)
{
//YOUR
Thread.sleep(35000);
}
}
finally
{
new File("f:\\test.lock").deleteOnExit();
}
}