12

Short version: Why should File.createNewFile() not be used for file locking? Or more specifically: Are there issues if it is used to lock an applications data directory?


Details:

I would like to protect my applications data directory using a lock file: If the file lock exists, the directory is locked and the application exits with an error message. If it does not exist it will be created and the application continues. On exit the file will be deleted.

The lock will not be created that often (i.e. performance is not an issue) and I have no problem with manually deleting the lock file in case of some error (i.e. failing to delete the file is not an issue).

The code looks something like this:

File lockFile = new File("lock"); boolean lockCreated = lockFile.createNewFile(); if (lockCreated) { // do stuff lockFile.delete(); } else { System.err.println("Lockfile exists => please retry later"); // alternative: Wait and retry e.g. 5 times } 

Now I'm a bit confused about the Javadoc of createNewFile():

Atomically creates a new, empty file named by this abstract pathname if and only if a file with this name does not yet exist. The check for the existence of the file and the creation of the file if it does not exist are a single operation that is atomic with respect to all other filesystem activities that might affect the file.

Note: this method should not be used for file-locking, as the resulting protocol cannot be made to work reliably. The FileLock facility should be used instead.

What are the potential problems mentioned in the note, considering the existence check and file creation are atomic?

This forum post from December 2007 indicates there are "significant platform differences" according to the Javadoc of File.delete() (although I cannot find such a statement since at least Java SE 1.4.2). But even if there would be such differences: Could they really cause the locking to fail (i.e. two processes think the data directory is usable at the same time)?


Note: I do not want any of the following:

  • Lock a file so that no other process can access and/or modify it (most information I found seems to discuss this issue).
  • Make sure no other process can remove the lock.
  • Synchronize multiple threads of the same JVM (although I think my solution should be able to handle that too).
5
  • 1
    depends on what they mean by "atomic". there's atomic-within-your-own-app, and atomic-for-all-apps-on-the-system. I'd suspect it's atomic for your app only, and can't do anything to protect some other parallel process jumping in and sniping the file away from you. Commented Nov 10, 2014 at 18:49
  • 2
    You could bail on using a file, and just open a port. Commented Nov 10, 2014 at 18:58
  • 1
    @MarcB: I expected the Javadoc to mean systemwide atomicity: "… are a single operation that is atomic with respect to all other filesystem activities…". But good point, did not think about that… Commented Nov 11, 2014 at 19:12
  • @MarkW: Good idea. But I think I'll stick to my file based solution, unless someone comes up with a reason not to. The application does not need to be bullet proof after all… ;-) Commented Nov 11, 2014 at 19:12
  • 1
    I looked at the jgit source code and they are using the same approach (LockFile). As pointed out in another answer, I guess this is kind of valid for a local fs. Commented Jul 18, 2017 at 23:07

2 Answers 2

2

The Javadoc of Files.createFile(…), part of java.nio.file available since Java 7, repeats the promise of atomicity but does not mention anything about file based locking.


My reasoning:

  • Either the newer method (from java.nio.file.Files) is affected by the same (or similar) problems as the older one (from java.io.File) and the Javadoc is simply missing this information…
  • … or the newer method actually behaves more predictably and correct.

Given the error handling and specification in java.nio.file has generally been improved compared to the File class (existing ever since JDK 1.2), I assume the second alternative is correct.


My conclusion: Using Files.createFile(…) is fine for this use case.

Sign up to request clarification or add additional context in comments.

1 Comment

Your conclusion could be clearer in my opinion: Do you suggest NOT using File.createNewFile() and ONLY Files.createFile() instead? Because not only is the note missing in Javadoc of the latter, but the implementation seems totally different as well. Even though in both cases calls seem to end in the same native calls using the same arguments: File: github.com/openjdk/jdk/blob/master/src/java.base/windows/native/… Files: github.com/openjdk/jdk/blob/master/src/java.base/windows/…
1

The short answer: reliable file based locking in Java is not practical.

The long answer: The issue with file based locking, in any OS, always comes down to what kind of storage system the file comes from. Almost all network accessed file systems (NFS, SAMBA, etc) have very unreliable (or at least unpredictable) synchronizations on file creates or deletes that make a general Java-ish approach inadvisable. In certain OSes, using local file systems, you can sometimes get what you desire. But you need to understand the underlying file system and its characteristics and proceed with care.

1 Comment

Thanks for your answer! I understand network file systems behave unpredictable. For me the Javadoc sounds pretty strict though. So either the Javadoc is correct and it is guaranteed that the check and file creation is atomic (at least for local file systems) or it is not and the Javadoc is wrong and should be reformulated (e.g. on a best effort basis…). Adding a rather unspecific note should not invalidate the guarantees made before…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.