Skip to content
Advertisement

Java Synchronized on the same file, but not different

I have this static class:

public class FileManager{
    ....
    public static void writeOnFile(String something, String filepath){
        File f= new File(filepath);

        // Append
        PrintWriter writer = new PrintWriter(new FileWriter(f, true));
        writer.append(something);
    }
    ...
}

that have lots of methods and this one above is one of these.

what I would like to do is that if two callers write to the same file, the writing should be done in mutual exclusion. But when callers write to different files, this doesn’t happen (they don’t write in mutual exclusion).

This versione below:

public class FileManager{
    ....
    public synchronized static void writeOnFile(String something, String filepath){
        File f= new File(filepath);

        // Append
        PrintWriter writer = new PrintWriter(new FileWriter(f, true));
        writer.append(something);
    }
    ...
}

I don’t think that’s what I want to accomplish. In this case the callers will write in mutual exclusion even if the files they write to are different.

I wanted to ask: this second version:

public class FileManager{
    ....
    public static void writeOnFile(String something, String filepath){
        File f= new File(filepath);

        // Append
        synchronized(f){
            PrintWriter writer = new PrintWriter(new FileWriter(f, true));
            writer.append(something);
        }
    }
    ...
}

would work?. if not, would I have to create an object that contains the filepath of each file in order to use the locks as I would like?

Advertisement

Answer

Synchronization will only work if done on the same actual object. Your second version will not work because it creates a new object, and therefore a new lock. What you would need is a registry of locks. A small example, using not synchronized but ReentrantLock:

private static final Map<String, Lock> LOCKS = new ConcurrentHashMap<>();

...

Lock lock = LOCKS.computeIfAbsent(filepath, p -> new ReentrantLock());
lock.lock();
try {
    ....
} finally {
    lock.unlock();
}

The combination of a ConcurrentHashMap and computeIfAbsent should result in the same Lock object each time the method is called with the same filepath value.

An alternative is perhaps to use FileLock. That uses the native locking mechanism (if it actually exists), and is based on actual files, not Java objects.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement