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:
process: 1 lock aquired: sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive invalid
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
Can someone point me towards my error please?
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?
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.
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?
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.
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.