This week's book giveaway is in the OCMJEA forum. We're giving away four copies of OCM Java EE 6 Enterprise Architect Exam Guide and have Paul Allen & Joseph Bambara on-line! See this thread for details.
Ok, so I'm working with FileLocks in my book. According to the javadoc for this class:
File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine.
To me this should mean that if I acquire a FileLock in one thread of my java application I should still be able to manipulate that file from any other thread of said application. The code below however is giving me different results.
I have a text file setup at the specified location which contains a "1" and will get the following output:
only if I uncomment line 14, releasing this lock before my scanner attempts to access the file. If I leave this line commented I get the following exception:
Exception in thread "Main Thread" java.util.NoSuchElementException at java.util.Scanner.throwFor(Scanner.java:838)
The javadoc doesn't say that if you lock a file in one thread, you can freely manipulate it in any other thread. It says that file locks aren't suitable for controlling access between threads in the same JVM. That could mean many things including (and this is generally the case, although it's platform and implementation dependent) multiple threads in the same JVM will be excluded for some operations, and not for others. Based on the documentation, the most conservative assumption is that you should depend neither on the lock restricting nor allowing access to other threads in the same JVM.
Thanks for the response Ernest. I really should have been more concise in my description of the problem. The code example that I give doesn't actually do anything multi-threaded. It locks the file and then attempts to read from that file within the same thread. I just meant to show in my description that what the code is doing is narrower than the conditions specified in the javadoc as I understand them.
Much less importantly for these purposes (and this may be nitpicking but it leaves me a bit confused) while I see that the second sentence in the quoted statement from the javadoc indeed says only that "They are not suitable for controlling access to a file by multiple threads within the same virtual machine", the first sentance "File locks are held on behalf of the entire Java virtual machine" at least seems to strongly imply that any thread in the same JVM should be able to freely manipulate this file. Do you disagree with that?
Well, the other way to interpret it is that they didn't bother to say anything about same-thread access because you already have control of that. That's not the problem file locks are intended to solve, so they didn't bother commenting on it.
I would say that the docs here are not very clear, and it would be nice if they talked more explicitly about what you can and can't expect regarding file lock behavior within a single JVM. The short answer, though, is that behavior can vary drastically based on the platform. Once you've got a lock on a file, you should really only access the file using the same FileChannel that you used to acquire the lock - or with the file stream or random access file associated with the channel. Attempting to access using another object, or to acquire a second lock, may or may not work, depending mostly on the operating system,. There really are no guarantees.
Joined: Aug 28, 2009
Once you've got a lock on a file, you should really only access the file using the same FileChannel that you used to acquire the lock - or with the file stream or random access file associated with the channel.
Thank you, Mike. That makes tonnes of sense. I couldn't understand what the use of locks were if locking a file prevented me from interacting with it even within the same thread.
I have one other question if you happen to know the answer. If I try to get a file lock from a channel which was pulled from a FileInputStream I get the following exception:
I'm told by my book that calling getChannel() on a FileInputStream or a FileOutputStream will return a Channel which is open for reading or writing respectively and that calling getChannel() on a RandomAccessFile will return a Channel which is open for reading and writing or reading only if said RandomAccessFile was set up in "rw" or "r" modes respectively.
That means that in order to read from a file, while it is locked, one would be forced to use the RandomAccessFile class. Is that right? ie is there any other way to get a channel or a file lock other than that?
Joined: Mar 05, 2008
Emilio Kazwell wrote:That means that in order to read from a file, while it is locked, one would be forced to use the RandomAccessFile class. Is that right?
If you want to read from and write to a file, using the same lock, then yes (as far as I know).
Alternately you could read from the file using one lock, close the reader and release the lock, then open a writer with a new lock to write to the file. This is easier, but leaves a small gap between reading and writing. I don't know what you're trying to do, so I don't know if this is a problem or not.
If you use the RandomAccessFile to get a FileChannel and then get a single read/write FileLock, then you may also benefit from methods like Channels.newReader() and Channels.newWriter(). These allow you to use Readers and Writers for the same file the RAF is attached to. This may be useful if you need or prefer those APIs to RandomAccessFile.
That exception also occurs when you try to get an exclusive lock on a read-only channel (there is a corresponding error when you try to get a shared lock on a write-only channel).
Instead of doing FileInputStream#getChannel()#lock() you would use the overloaded version of the lock which takes 3 parameters - and make sure the last one is set to true.
Of course, this would leave you with a different error (OverlappingLock or something like that) assuming you try to lock the entire file with both the read and write locks.
Which brings us to the solution to your last question. You can have independent file locks to the same file, one read and one write, at the same time, but they can not overlap. You have to lock blocks of the file for reading and blocks for writing, and not let the two overlap the same bytes. You use the overloaded version of lock() which takes 3 parameters
1) long position: The starting byte to lock at
2) long size: The number of consecutive bytes to lock
3) boolean shared: True for a read Stream and False for a write Stream.
Joined: Aug 28, 2009
Ok, I think I understand these classes better now.