TL DR: It's not about locks, but about how files open. What you see in io is the best Windows that you could make before Windows 2000, and this happened even when the files were open for reading only - it was impossible to delete this file. What you see in nio is an improvement that takes advantage of the new feature introduced with Windows 2000, but you can still have your previous behavior in nio if you want. It was decided not to port this opportunity to what io does.
Full story: I deleted all the code related to locking (see below), as well as writing files, and it works exactly the same as your code; however, I also found that if you specify ExtendedOpenOption.NOSHARE_DELETE when opening the "nio" channel, then the behavior when trying to delete either of the two files is the same (uncomment it in the code and try). Also found this question , and he has some explanation, not sure if it will help.
import java.io.*; import java.lang.management.ManagementFactory; import java.nio.*; import java.nio.channels.*; import java.nio.file.*; public class NioIoLock { public static void main(String[] args) throws IOException, InterruptedException { String workDir = System.getProperty("user.dir"); FileChannel channelIo, channelNio; FileLock lockIo, lockNio;
Update 1: Actually, I still donβt know the reason for this, but the mechanics are clear: the RandomAccessFile constructor ultimately calls the following native code from the winFileHandleOpen method from io_util_md.c:
FD winFileHandleOpen(JNIEnv *env, jstring path, int flags) { ... const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; ... // "sharing" not updated anymore h = CreateFileW( pathbuf, /* Wide char path name */ access, /* Read and/or write permission */ sharing, /* File sharing flags */ NULL, /* Security attributes */ disposition, /* creation disposition */ flagsAndAttributes, /* flags and attributes */ NULL); ... }
So, the FILE_SHARE_DELETE flag FILE_SHARE_DELETE not set, and you cannot do anything to set it. On the other hand, when calling java.nio.channels.FileChannel.open(Path, OpenOption...) , this flag is taken into account:
private static FileDescriptor open(String pathForWindows, String pathToCheck, Flags flags, long pSecurityDescriptor) throws WindowsException { ... int dwShareMode = 0; if (flags.shareRead) dwShareMode |= FILE_SHARE_READ; if (flags.shareWrite) dwShareMode |= FILE_SHARE_WRITE; if (flags.shareDelete) dwShareMode |= FILE_SHARE_DELETE; ...
Update 2: From JDK-6607535 :
The suggestion to change the sharing mode is RFE 6357433. It would be great to do this, but it might break existing applications (since the current behavior exists with jdk1.0). Adding custom mode to RandomAccessFile to work with Windows problems is probably not appropriate either. In addition, there are some suggestions that this may help with the problem of deleting files that have file associations. This is not the case, as file association still prevents file deletion. In any case, for jdk7 we are working on a new file system API that will cover some of the requirements here. The Windows implementation makes open files can be deleted.
Also see JDK-6357433 referenced by:
The client pointed to the java.net forums that opening a file in Windows using FileInputStream causes other processes not to delete the file. This is the expected behavior because the code is currently written because the exchange flags specified when the file was opened are FILE_SHARE_READ and FILE_SHARE_WRITE. See Io_util_md.c, fileOpen. However, Windows 2000 provides a new flag, FILE_SHARE_DELETE, which allows another process to delete the file while it is still open.
and finally
WORK AROUND
For jdk7, a workaround is to use the new file system API. So instead of the new FileInputStream (f) and the new FileOutputStream (f), use f.toPath (). NewInputStream () and f.toPath (). NewOutputStream ().