In a multi-threaded application where multiple threads are accessing a resource at the same time, it becomes necessary to handle concurrent modifications.
Suppose a file is being written by a thread and at the same time it is being read by another thread. In such case, the thread reading the file will not have the updated contents.
Similarly, if two threads are writing a file at the same time, then there are chances of the file becoming corrupt.
To avoid such situations, there should be a mechanism that locks the file while writing or reading in java. Fortunately, java NIO has the facility to lock a file and this article will explain how to to that.
java nio file lock
java.nio.FileChannel
provides a channel for reading and writing files. This class also has methods to acquire locks on the file that is pointed by the underlying channel.
When a lock is acquired on a file by a thread or process, then any other thread or process cannot access the file till the thread or process holding the lock either releases it or the process terminates.
Following are the two methods of this class that provide an exclusive lock to a file.
- lock: Tries to acquire lock on the file represented by the underlying channel. This method blocks if the lock is not immediately available. This method may throw below exceptions
java.nio.channels.ClosedChannelException
: If the channel is closed when it tries to gain the lock.java.nio.channels.OverlappingFileLockException
: If another thread or process is holding a lock at the same region of the file or over the entire file.java.nio.channels.NonWritableChannelException
: If the channel is not opened in write mode.java.nio.channels.FileLockInterruptionException
: If a thread is blocked for getting a lock and in the mean time it is interrupted.java.io.IOException
: When an IO error occurs other than above.
- tryLock: Tries to acquire lock on the file represented by the underlying channel. This method does not block if the lock is not available and returns immediately. It returns
null
if it fails to acquire lock or throws appropriate exception out of the below.java.nio.channels.ClosedChannelException
: Thrown if the channel is closed at the time of acquiring lock.java.nio.channels.OverlappingFileLockException
: If another thread or process is holding a lock at the same region of the file or over the entire file.java.io.IOException
: When an IO error occurs other than above.
Note: Both the above methods also have an overloaded version which allows to lock a block of file. It accepts the position and the range of the file that it will try to get a lock on.
lock file java example
Below program is used to lock a file before writing using java.nio.FileChannel
.
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.io.File;
public class FileLockExample {
public static main(String[] args) {
// open file in read-write mode
RandomAccessFile randomAccessFile = new RandomAccessFile(
new File("e:/demo.txt"), "rw");
try {
// get channel
FileChannel channel = randomAccessFile.getChannel();
// get lock
FileLock tryLock = channel.lock();
String data = "text to write";
// write to file
randomAccessFile.write(data.getBytes());
// release lock
tryLock.release();
// close file
randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Above method uses java.io.RandomAccessFile for writing to a file, you can also use other methods of writing a file in java in the same place.
While the file is locked for writing, try to read it in another thread using any of the file reading methods in java and you will get the below exception
java.io.IOException: The process cannot access the file because another process has locked a portion of the file
at java.base/java.io.FileInputStream.readBytes(Native Method)
at java.base/java.io.FileInputStream.read(FileInputStream.java:279)
at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.base/sun.nio.cs.StreamDecoder.read0(StreamDecoder.java:127)
at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:112)
at java.base/java.io.InputStreamReader.read(InputStreamReader.java:168)
which clearly shows that the file is locked.
Similarly, if one thread or process is holding the file’s lock and you try to get another lock in a different thread, then you will get a java.nio.channels.OverlappingFileLockException
as below
Exception in thread “Thread-1” java.nio.channels.OverlappingFileLockException
at java.base/sun.nio.ch.FileLockTable.checkList(FileLockTable.java:229)
at java.base/sun.nio.ch.FileLockTable.add(FileLockTable.java:123)
at java.base/sun.nio.ch.FileChannelImpl.lock(FileChannelImpl.java:1109)
A file can also be locked for only reading. Just change the mode when creating an object of type java.io.RandomAccessFile
to read.
Hit the clap if you liked the article.