What is a FileLock in Java NIO, and how do shared vs. exclusive locks and lock() vs. tryLock() work?
answer
- shared = many readers; exclusive = one writer, excludes all
- lock() blocks; tryLock() returns null on contention
- advisory + OS-dependent, JVM-wide not per-thread
- OverlappingFileLockException for same-JVM overlap
- release()/close()/JVM-exit frees it; shared needs READ, exclusive needs WRITE
basics
~20 sA FileLock lets a program lock a file (or part of it) so processes coordinate access. A shared lock allows multiple readers; an exclusive lock allows only one writer. lock() waits until it can get the lock; tryLock() returns immediately, giving null if the lock isn't available.
solid answer
~50 sFileChannel.lock() and tryLock() acquire a FileLock over a region of a file to coordinate access between processes (and, since Java's locks are process-wide, you must avoid overlapping locks within the same JVM). Locks come in two kinds: shared (read) locks, which several holders can hold simultaneously over the same region, and exclusive (write) locks, which exclude all other locks on that region. The blocking lock() waits until the lock is granted; tryLock() attempts once and returns null (or throws OverlappingFileLockException for same-JVM overlap) instead of blocking. Crucially, FileLocks are typically advisory and OS-dependent: they coordinate only programs that also check the lock, and shared locks require the channel open for read while exclusive locks require it open for write. You release with lock.release(), and a lock is also released when the channel closes or the JVM exits. Use try-with-resources or finally to avoid leaking locks.
code
java · 16 linesimport java.nio.channels.*;
import java.nio.file.*;
import static java.nio.file.StandardOpenOption.*;
try (FileChannel ch = FileChannel.open(Path.of("app.lock"), READ, WRITE)) {
FileLock lock = ch.tryLock(); // non-blocking, exclusive, whole file
if (lock == null) {
System.out.println("Another instance is running");
return;
}
try {
// ... protected work ...
} finally {
lock.release();
}
}go deeper
Knows shared = multiple readers, exclusive = single writer, lock() waits, tryLock() returns immediately/null.
Explains advisory nature, JVM-wide scope, OverlappingFileLockException, channel access requirements, and lock lifecycle/release.
Discusses cross-process protocols (single-instance, file-based coordination), OS/filesystem portability of locks, and choosing blocking vs. non-blocking acquisition.
Designs robust cross-process coordination accounting for advisory semantics on network/edge filesystems, lock-loss on crash, fencing, and when to prefer a real lock service over file locks.
## The problem: coordinating access to a file When two programs (or two JVMs) touch the same file, you can get corruption: one writes while another reads a half-updated record. A **FileLock** is a coordination mechanism: a program claims a lock on a file region, and other cooperating programs respect that claim. ## Shared vs. exclusive There are two lock types, the classic *readers-writer* pattern: - **Shared lock (read lock):** many programs can hold a shared lock on the *same* region at once. Use it when you only read and want to ensure no one is writing. - **Exclusive lock (write lock):** only one holder, and it excludes *all* other locks (shared or exclusive) on that region. Use it when you write. So: shared+shared is allowed; shared+exclusive and exclusive+exclusive conflict on overlapping regions. ## The API ```java try (FileChannel ch = FileChannel.open(path, READ, WRITE); FileLock lock = ch.lock()) { // blocking, exclusive, whole file // ... safe to read/write ... } // lock auto-released by close() ``` - `FileChannel.lock()` — blocking; acquires an **exclusive** lock over the whole file. Waits until granted. - `FileChannel.lock(long position, long size, boolean shared)` — lock a **region**; `shared=true` for a shared lock. - `FileChannel.tryLock()` / `tryLock(position, size, shared)` — **non-blocking**: try once; return the `FileLock` if granted, or **`null`** if another program holds a conflicting lock. It does *not* wait. - `FileLock.release()` — release it. `FileLock` is `AutoCloseable`, so try-with-resources releases it too. Access requirements: a **shared** lock needs the channel open for **reading**; an **exclusive** lock needs it open for **writing**. Requesting the wrong kind for how you opened the channel throws `NonReadableChannelException` / `NonWritableChannelException`. ## lock() vs. tryLock() - `lock()` **blocks** the calling thread until it can acquire the lock (or throws if interrupted/closed). Good when you must proceed and are willing to wait. - `tryLock()` **returns immediately**. On contention it gives `null` rather than blocking — ideal for "single-instance app" checks or avoiding deadlock-prone waits. You branch on the result. ## Two big caveats 1. **Advisory, OS-dependent.** On most platforms file locks are **advisory**, not mandatory: they only stop programs that *also* ask for / check the lock. A program that ignores locking can still read/write the file. Behavior (and whether locks are mandatory) varies by OS and filesystem (e.g., network filesystems may not honor them). So treat FileLock as a *cooperation protocol*, not a hard gate. 2. **JVM-wide, not thread coordination.** A `FileLock` is held by the **whole JVM**, not a thread. It coordinates *between* processes. Trying to acquire a lock that **overlaps** a region already locked by the *same* JVM throws `OverlappingFileLockException`. So you cannot use FileLock to synchronize threads inside one JVM — use normal Java locks (`synchronized`, `ReentrantLock`) for that. ## Lifecycle A lock is released by `release()`, by closing the channel, or when the JVM terminates. Always release in `finally` or via try-with-resources to avoid stranding a lock that blocks other processes. ## Summary FileLock coordinates file access across processes. Shared locks allow concurrent readers; exclusive locks allow a single writer and exclude everyone. `lock()` blocks until granted; `tryLock()` returns immediately (null on contention). Remember they're usually advisory, JVM-wide (OverlappingFileLockException for same-JVM overlap), require matching channel access, and must be released.
- What does tryLock() return when another process already holds a conflicting lock?It returns null immediately instead of blocking. (If the conflict is with a lock held by the same JVM, it throws OverlappingFileLockException rather than returning null.)
- Can you use FileLock to synchronize two threads in the same JVM?No. FileLocks are held at the JVM/process level, not per thread, and overlapping requests in one JVM throw OverlappingFileLockException. Use synchronized or ReentrantLock for intra-JVM thread coordination.
It's a sign-up sheet on a meeting room: a shared lock is several people noting they're just observing; an exclusive lock is one person booking it solo. But it only works if everyone checks the sheet (advisory) — someone ignoring it can still walk in.
saying these in an interview costs you the question
- Treating FileLock as mandatory enforcement — it's usually advisory and only binds cooperating programs
- Using FileLock to coordinate threads within one JVM (it's process-level; throws OverlappingFileLockException on overlap)
- Thinking tryLock() blocks — it returns immediately (null on contention)
- Forgetting that a shared lock needs the channel open for read and an exclusive lock for write
- Leaking a lock by not releasing it (other processes stay blocked)