tags:

views:

365

answers:

3
+1  Q: 

Java File Locking

I have several threads (some of which are spawned by Process X, others by Process Y, et cetera), and each thread needs to write to a file MyFile. However, if Thread T1 starts writing to MyFile first, then, when Thread T2 starts writing, it needs to wait for T1 to release the file, so that it can read the contents that were written in Thread T1. In other words, each thread would have a finalizeThread method, like so:

private void finalizeThread() {
    File f = new File("MyFile.dat");
    f.createNewFile();  // atomically creates the file, if it doesn't exist
    locked_section {
        readContentsFromFile(f); // read contents if some other thread already modified the file
        modifyContentsFromFile(f); // modify
        writeFile(f); // write, so that new threads can see the content modified by this thread
    }
}

My question is: How can I accomplish the locked_section in the above code? I was looking into the FileLock class, but it says in the Javadoc that "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.".

+2  A: 

You'll want to synchronize on some object. For example:

synchronized(fileLockObject) {
    readContentsFromFile(f);
    modifyContentsFromFile(f);
    writeFile(f);
}
Anon.
Hello Anon., thanks for your comment. However, I cannot do that, since these threads are spawned by different processes, and I can not share that object among all threads, hence the need for another approach. These are also not standard Java `concurrency.*` threads, but threads that are created by an Oracle API.
JG
If they are different processes (and thus separate VMs), you can just use the `FileLock` class.
Anon.
Yes, but some are spawned by the same process. But yes, perhaps a hybrid strategy would work. Thanks.
JG
@JG - no need for a hybrid strategy. FileLock will work just fine whether the threads are in the same process or different processes.
Stephen C
@Stephen: That's not what the documentation says.
Anon.
+2  A: 

If the file is only accessed from your program, the synchronized lock object is okay. But if you want to protect the file from being changed by other programs while you're working on it, you can use Java's file locking features in java.nio.channels.FileLock (example). As the text says, mind that on some operating systems, programs can still change files if they don't check for an existing file lock.

AndiDog
Thanks for the feedback. Yes, it is only accessed by my program, and every thread will/can check for the existence of a lock before proceeding. The problem is that the API I'm using can spawn threads from several different processes, and some threads from within the same proces, and I'm afraid there may be problems associated with that, since the `FileLock` javadoc mentions it.
JG
Maybe i'm misunderstanding something, but what do you mean you have threads spawned by different processes? A process has its own address space, and any threads it creates shared that address space. Do you have multiple processes each spawning multiple threads which may try to write to the same file?
darren
The Javadoc says: "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. File-lock objects are safe for use by multiple concurrent threads."Aren't the last two sentences mutually exclusive?? I think somebody will have to take a look at the source code...In the next paragraph it says "This file-locking API is intended to map directly to the native locking facility of the underlying operating system."So it *should* work just like flock (Linux) or LockFileEx(Windows).
AndiDog
No, it makes sense. Regarding those two sentences, the first one says "don't use a File lock to control access to a file BETWEEN threads", and the second says "multiple threads can use the same File lock as long as they're aware that they all have the same File lock"
danben
@danben: Okay, thanks for the circumscription, now it makes sense :)
AndiDog
+1  A: 

Instead of sharing a lock, maybe you could have a separate process that was responsible for maintaining a lock on the file. To begin your read/modify/write step, a Thread would have to ask this central process for the lock via HTTP, or messaging, or whatever you like. If the request is denied, the Thread would go to sleep, wake up, and try again. Otherwise the Thread would read/modify/write and then tell the locking process that it is releasing the lock.

danben
If you're going to use a central process it's probably better if this process handles the reading/writing itself, so you don't have to worry about what happens when a thread dies after being issued the lock (well you do, but it's less complicated).
wds