Java FileLock for Reading and Writing

后端 未结 3 1300
庸人自扰
庸人自扰 2020-12-03 04:53

I have a process that will be called rather frequently from cron to read a file that has certain move related commands in it. My process needs to read and write to this dat

相关标签:
3条回答
  • 2020-12-03 05:34

    (a) Are you aware that locking the file won't keep other processes from touching it unless they also use locks?
    (b) You have to lock via a writable channel. Get the lock via a RandomAccessFile in "rw" mode and then open your FileInputStream. Make sure to close both!

    0 讨论(0)
  • 2020-12-03 05:47

    I wrote a test program and bash commands to confirm the effectivity of the file lock:

    import java.io.File;
    import java.io.RandomAccessFile;
    import java.nio.channels.FileLock;
    
    public class FileWriterTest
    {
        public static void main(String[] args) throws Exception
        {
            if (args.length != 4)
            {
                System.out.println("Usage: FileWriterTest <filename> <string> <sleep ms> <enable lock>");
                System.exit(1);
            }
    
            String filename = args[0];
            String data = args[1];
            int sleep = Integer.parseInt(args[2]);
            boolean enableLock = Boolean.parseBoolean(args[3]);
    
            try (RandomAccessFile raFile = new RandomAccessFile(new File(filename), "rw"))
            {
                FileLock lock = null;
                if (enableLock)
                {
                    lock = raFile.getChannel().lock();
                }
    
                Thread.sleep(sleep);
                raFile.seek(raFile.length());
                System.out.println("writing " + data + " in a new line; current pointer = " + raFile.getFilePointer());
                raFile.write((data+"\n").getBytes());
    
                if (lock != null)
                {
                    lock.release();
                }
            }
        }
    }
    

    Run with this bash command to check it works:

    for i in {1..1000}
    do
    java FileWriterTest test.txt $i 10 true &
    done
    

    You should see the writing only happening once every 10ms (from the outputs), and in the end all numbers to be present in the file.

    Output:

    /tmp wc -l test.txt
    1000 test.txt
    /tmp
    

    The same test without the lock shows data being lost:

    for i in {1..1000}
    do
    java FileWriterTest test.txt $i 10 false &
    done
    

    Output:

    /tmp wc -l test.txt
    764 test.txt
    /tmp
    

    It should be easy to modify it to test the tryLock instead.

    0 讨论(0)
  • 2020-12-03 05:54

    It would be better if you created the lock using tryLock(0L, Long.MAX_VALUE, true).

    This creates a shared lock which is the right thing to do for reading.

    tryLock() is a shorthand for tryLock(0L, Long.MAX_VALUE, false), i.e. it requests an exclusive write-lock.

    0 讨论(0)
提交回复
热议问题