A question about file lock

In a situation that one program grab a read lock on a file and another program want to write to the file. How does the first program prevent the second program from modifying the file? According to Java API doc, a shared lock prevents other concurrently-running programs from acquiring an overlapping exclusive lock. Before the second program acquiring a exclusiev lock, it must create an object of FileOutputStream, see below:

FileOutputStream output =new FileOutputStream(filename);

FileChannel channel = output.getChannel();

FileLock lock = channel.tryLock();

The programs are running under Linux system, the file-locking facilities of which is advisory. So the first line will work successfully. But at this time, the file has already erased. Althought the tryLock()

will return null for that the first program has grabed a shared lock, the first program will read incorrectly. How to solve this issue?

Thanks.

[992 byte] By [youhaodiyia] at [2007-11-27 10:10:51]
# 1

Both programs have to use locking, not just one of them.

ejpa at 2007-7-28 15:09:13 > top of Java-index,Core,Core APIs...
# 2

Yes, both of the programs have used file locking. But for the program using exclusive lock, it will erase the content of the file before it acquire the lock.

youhaodiyia at 2007-7-28 15:09:13 > top of Java-index,Core,Core APIs...
# 3

Well it will have to try opening the file for input-output and write-locking it first. If that succeeds, open it for output and write-lock it immediately. There may be some timing window issues in here.

ejpa at 2007-7-28 15:09:13 > top of Java-index,Core,Core APIs...
# 4

What do you mean by opening the file for input-output and write-locking it first? See my programs below:

The program for reading

import java.io.*;

import java.nio.channels.*;

public class LockRead{

public static void main(String []args){

try{

FileInputStream input = new FileInputStream("test.txt");

FileChannel channel = input.getChannel();

FileLock lock = channel.tryLock(0,Long.MAX_VALUE,true);

Thread.sleep(5000);

lock.release();

}catch(Exception ex){

ex.printStackTrace();

}

}

}

The program for writing:

import java.io.*;

import java.nio.channels.*;

public class LockWrite{

public static void main(String []args){

try{

FileOutputStream output = new FileOutputStream("test.txt");

FileChannel channel = output.getChannel();

FileLock lock = channel.tryLock();

}

catch(Exception ex){

ex.printStackTrace();

}

}

}

How do i open a file for input and ouput?

youhaodiyia at 2007-7-28 15:09:13 > top of Java-index,Core,Core APIs...
# 5

with java.io.RandomAccessFile

ejpa at 2007-7-28 15:09:13 > top of Java-index,Core,Core APIs...
# 6

> Well it will have to try opening the file for

> input-output and write-locking it first. If that

> succeeds, open it for output and write-lock it

> immediately. There may be some timing window issues

> in here.

Why do I open it for output again if I have already locked it. Can I use the RandomAccessFile object for write-locking? For example:

import java.io.*;

import java.nio.channels.*;

public class LockWrite{

public static void main(String []args){

try{

RandomAccessFile raFile = new RandomAccessFile("test.txt","rw");

FileChannel raChannel = raFile.getChannel();

FileLock raLock = raChannel.tryLock();

if(raLock != null){

raFile.writeChars("test");

raLock.release();

}

}

catch(Exception ex){

ex.printStackTrace();

}

}

}

youhaodiyia at 2007-7-28 15:09:13 > top of Java-index,Core,Core APIs...
# 7

1. Because you want to re-create it from scratch? If you don't need to do that, you can write through the RandomAccessFile's channel.

2. Yes.

ejpa at 2007-7-28 15:09:13 > top of Java-index,Core,Core APIs...
# 8

If I want to re-create it from scratch, my program will look like this:

import java.io.*;

import java.nio.channels.*;

public class LockWrite{

public static void main(String []args){

try{

RandomAccessFile raFile = new RandomAccessFile("test.txt","rw");

FileChannel raChannel = raFile.getChannel();

FileLock raLock = raChannel.tryLock();

if(raLock != null){

raLock.release();

raFile.close();

FileOutputStream output = new FileOutputStream("test.txt");

FileChannel channel = output.getChannel();

FileLock lock = channel.tryLock();

//...

}

}

catch(Exception ex){

ex.printStackTrace();

}

}

}

Is it correct? If it is, there will be race condition between these lines:

raLock.release();

raFile.close();

FileOutputStream output = new FileOutputStream("test.txt");

After the raLock release the lock and before it get the output lock, the other program may grab the shared lock. It will not solve the program.

youhaodiyia at 2007-7-28 15:09:13 > top of Java-index,Core,Core APIs...
# 9

Don't create the FileOutputStream, keep using the original channel and call FileChannel.setLength().

ejpa at 2007-7-28 15:09:13 > top of Java-index,Core,Core APIs...
# 10

> Don't create the FileOutputStream, keep using the

> original channel and call FileChannel.setLength().

I didn't find setLength() in FileChannel class. I use jdk1.6.0. I know a same method in RadomAccessFile. Do you mean this? Why do I need a call to setLength()?

youhaodiyia at 2007-7-28 15:09:13 > top of Java-index,Core,Core APIs...
# 11

Sorry, yes I meant RandomAccessFile.setLength(). Set it to zero.

ejpa at 2007-7-28 15:09:13 > top of Java-index,Core,Core APIs...