使用FileLock 的标准方法是打开文件,例如通过FileChannel.open,然后是tryLock。锁的存在不会阻止其他进程打开文件。
这可以通过以下程序来证明:
import java.io.IOException;
import java.nio.channels.*;
import java.nio.file.*;
class Locking {
public static void main(String[] args) throws IOException, InterruptedException {
if(args.length > 0) {
String me = String.format("%6s ", ProcessHandle.current());
Path p = Paths.get(args[0]);
try(FileChannel fc = FileChannel.open(p,
StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
FileLock l = fc.tryLock();
if(l == null) System.out.println(me + "could not acquire lock");
else {
System.out.println(me + "got lock");
Thread.sleep(3000);
System.out.println(me + "releasing lock");
l.release();
}
}
}
else {
Path p = Files.createTempFile("lock", "test");
String[] command = {
Paths.get(System.getProperty("java.home"), "bin", "java").toString(),
"-cp", System.getProperty("java.class.path"),
"Locking", p.toString()
};
ProcessBuilder b = new ProcessBuilder(command).inheritIO();
Process p1 = b.start(), p2 = b.start(), p3 = b.start();
p1.waitFor();
p2.waitFor();
p3.waitFor();
Files.delete(p);
}
}
}
打印类似的东西
12116 got lock
13948 could not acquire lock
13384 could not acquire lock
12116 releasing lock
可以是demonstrated online on tio.run
虽然此程序在 Windows 下运行相同,但此操作系统支持打开未共享的文件,防止其他进程打开。如果其他进程以这种方式打开了文件,我们甚至无法打开它来探测锁定状态。
这不是方式,Java 打开文件,但是,有一个非标准的打开选项来复制行为,com.sun.nio.file.ExtendedOpenOption.NOSHARE_WRITE。在最近的 JDK 中,它位于 jdk.unsupported 模块中。
当我们在Windows下运行如下扩展测试程序时
import java.io.IOException;
import java.nio.channels.*;
import java.nio.file.*;
import java.util.HashSet;
import java.util.Set;
class LockingWindows {
public static void main(String[] args) throws IOException, InterruptedException {
if(args.length > 0) {
String me = String.format("%6s ", ProcessHandle.current());
Path p = Paths.get(args[0]);
Set<OpenOption> options
= Set.of(StandardOpenOption.WRITE, StandardOpenOption.APPEND);
if(Boolean.parseBoolean(args[1])) options = addExclusive(options);
try(FileChannel fc = FileChannel.open(p, options)) {
FileLock l = fc.tryLock();
if(l == null) System.out.println(me + "could not acquire lock");
else {
System.out.println(me + "got lock");
Thread.sleep(3000);
System.out.println(me + "releasing lock");
l.release();
}
}
}
else {
Path p = Files.createTempFile("lock", "test");
String[] command = {
Paths.get(System.getProperty("java.home"), "bin", "java").toString(),
"-cp", System.getProperty("java.class.path"),
"LockingWindows", p.toString(), "false"
};
ProcessBuilder b = new ProcessBuilder(command).inheritIO();
for(int run = 0; run < 2; run++) {
Process p1 = b.start(), p2 = b.start(), p3 = b.start();
p1.waitFor();
p2.waitFor();
p3.waitFor();
if(run == 0) {
command[command.length - 1] = "true";
b.command(command);
System.out.println("\nNow with exclusive mode");
}
}
Files.delete(p);
}
}
private static Set<OpenOption> addExclusive(Set<OpenOption> options) {
OpenOption o;
try {
o = (OpenOption) Class.forName("com.sun.nio.file.ExtendedOpenOption")
.getField("NOSHARE_WRITE").get(null);
options = new HashSet<>(options);
options.add(o);
} catch(ReflectiveOperationException | ClassCastException ex) {
System.err.println("opening exclusive not supported");
}
return options;
}
}
我们会得到类似的东西
2356 got lock
6412 could not acquire lock
9824 could not acquire lock
2356 releasing lock
Now with exclusive mode
9160 got lock
Exception in thread "main" java.nio.file.FileSystemException: C:\Users\...\Temp\lock13936982436235244405test: The process cannot access the file because it is being used by another process
at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:92)
at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108)
at java.base/sun.nio.fs.WindowsFileSystemProvider.newFileChannel(WindowsFileSystemProvider.java:121)
at java.base/java.nio.channels.FileChannel.open(FileChannel.java:298)
at LockingWindows.main(LockingWindows.java:148)
Exception in thread "main" java.nio.file.FileSystemException: C:\Users\...\Temp\lock13936982436235244405test: The process cannot access the file because it is being used by another process
at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:92)
at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108)
at java.base/sun.nio.fs.WindowsFileSystemProvider.newFileChannel(WindowsFileSystemProvider.java:121)
at java.base/java.nio.channels.FileChannel.open(FileChannel.java:298)
at LockingWindows.main(LockingWindows.java:148)
9160 releasing lock
与您的测试结果的相似性表明您与 Java 程序同时运行的 Windows 程序确实使用了这种模式。
对于您的 Java 程序,只要您不使用该模式,就不会出现此类问题。只有当您必须与另一个不使用协作锁定的 Windows 程序进行交互时,您才需要处理这个问题。