5

I'm writing a program that writes to a single file from both different threads on the same JVM and from different JVM's/processes. Is there a way to lock a file for both threads and processes, so that no matter how many threads/processes are trying to write at the same time, only 1 can write at a time?

Currently I have something similar to the following which works for locking threads, but not for blocking processes. If I try using FileLock on top of the implementation below it appears the synchronized stops working.

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import scripts.com.adz.commons.utils.FileUtilities;

import java.io.*;

public class Foo {
    public static void main(String[] args) throws IOException {
        Bar bar = new Bar();
        bar.start();

        while (true) {
            FileUtilities.writeObjectToFile("C:\\test.html", "foo");
        }
    }
}

class Bar extends Thread {
    @Override
    public void run() {
        while (true) {
            try {
                FileUtilities.writeObjectToFile("C:\\test.html", "bar");
            } catch (IOException ignored) {}
        }
    }
}

class FileUtilitiess {
    private static final Object _lock = new Object();

    public static <T> T readObjectFromFile(File file) throws IOException, ClassNotFoundException {
        synchronized (_lock) {
            final byte[] bytes = FileUtils.readFileToByteArray(file);

            ByteArrayInputStream bis = null;
            ObjectInputStream ois = null;

            try {
                ois = new ObjectInputStream(bis = new ByteArrayInputStream(bytes));

                return (T) ois.readObject();
            } finally {
                IOUtils.closeQuietly(ois);
                IOUtils.closeQuietly(bis);
            }
        }
    }

    public static void writeObjectToFile(File file, Object object) throws IOException {
        System.out.println("Sent object: " + object.toString());
        synchronized (_lock) {
            System.out.println("Writing object: " + object.toString());

            ByteArrayOutputStream bos = null;
            ObjectOutputStream oos = null;

            try {
                oos = new ObjectOutputStream(bos = new ByteArrayOutputStream());
                oos.writeObject(object);

                FileUtils.writeByteArrayToFile(file, bos.toByteArray());

                // - Start: For testing lock.
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException ignored) {}
                // - End: For testing lock.
            } finally {
                IOUtils.closeQuietly(oos);
                IOUtils.closeQuietly(bos);
            }
        }
    }
}
Adam Rivers
  • 51
  • 1
  • 2
  • you mean [FileLock](http://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileLock.html) ? – Olimpiu POP Jan 23 '15 at 15:25
  • FileLock doesnt work for multiple threads: "They are not suitable for controlling access to a file by multiple threads within the same virtual machine." – Adam Rivers Jan 23 '15 at 15:28
  • 1
    Show your code with `FileLock` in place; there should be no reason that the two can't coexist. My gut feel, however, is that you're using the wrong solution to whatever problem that you're trying to solve, and you would probably get better answers if you describe the problem and not your implementation. – kdgregory Jan 23 '15 at 15:33
  • All threads in a process share the same set of file locks. Actually, the native record locks do so in this way. Java just employs the OS capability. – Chao Jan 08 '17 at 05:17

1 Answers1

3

See FileLock javadoc:

File locks are held on behalf of the entire Java virtual machine.

That means that on the OS level different threads of your application will have the same right to access the locked region.

To lock the file access from different threads you have to encapsulate your file IO code and to enforce synchronized execution.

Jeor Mattan
  • 475
  • 3
  • 10