Java : FileLock with Examples

FileLock (Java SE 19 & JDK 19) API Examples.
You will find code examples on most FileLock methods.


Summary

A token representing a lock on a region of a file.

Class diagram

An example with the FileChannel.lock method.

public class Child {
    public static void main(String[] args) throws IOException, InterruptedException {
        final var pid = ProcessHandle.current().pid();
        System.out.println("  child : start (pid=" + pid + ")");

        TimeUnit.SECONDS.sleep(1);

        final var file = Path.of("lock.txt");
        try (final var fc = FileChannel.open(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {

            System.out.println("  child : lock start (pid=" + pid + ")");
            try (final var lock = fc.lock()) {

                System.out.println("  child :   *** lock OK! *** (pid=" + pid + ")");
                System.out.println("  child :   sleep 5 seconds ... (pid=" + pid + ")");
                TimeUnit.SECONDS.sleep(5);
            }

            System.out.println("  child : lock end (pid=" + pid + ")");
        }

        System.out.println("  child : end (pid=" + pid + ")");
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println("main : start");

        final var builder = new ProcessBuilder("java", "Child").inheritIO();
        final var p1 = builder.start();
        final var p2 = builder.start();

        p1.waitFor();
        p2.waitFor();

        System.out.println("main : end");
    }
}

// Result
// ↓
//> java Main
//main : start
//  child : start (pid=16164)
//  child : start (pid=11592)
//  child : lock start (pid=16164)
//  child :   *** lock OK! *** (pid=16164)
//  child :   sleep 5 seconds ... (pid=16164)
//  child : lock start (pid=11592)
//  child : lock end (pid=16164)
//  child :   *** lock OK! *** (pid=11592)
//  child : end (pid=16164)
//  child :   sleep 5 seconds ... (pid=11592)
//  child : lock end (pid=11592)
//  child : end (pid=11592)
//main : end

An example with the FileChannel.tryLock method.

public class Child {
    public static void main(String[] args) throws IOException, InterruptedException {
        final var pid = ProcessHandle.current().pid();
        System.out.println("  child : start (pid=" + pid + ")");

        TimeUnit.SECONDS.sleep(1);

        final var file = Path.of("lock.txt");
        try (final var fc = FileChannel.open(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {

            System.out.println("  child : lock start (pid=" + pid + ")");

            while (true) {
                try (final var lock = fc.tryLock()) {
                    if (lock != null) {
                        System.out.println("  child :   *** lock OK! *** (pid=" + pid + ")");
                        System.out.println("  child :   sleep 5 seconds ... (pid=" + pid + ")");
                        TimeUnit.SECONDS.sleep(5);
                        break;
                    } else {
                        System.out.println("  child :   *** lock NG! *** (pid=" + pid + ")");
                        System.out.println("  child :   sleep 1 second ... (pid=" + pid + ")");
                        TimeUnit.SECONDS.sleep(1);
                    }
                }
            }

            System.out.println("  child : lock end (pid=" + pid + ")");
        }

        System.out.println("  child : end (pid=" + pid + ")");
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println("main : start");

        final var builder = new ProcessBuilder("java", "Child").inheritIO();
        final var p1 = builder.start();
        final var p2 = builder.start();

        p1.waitFor();
        p2.waitFor();

        System.out.println("main : end");
    }
}

// Result
// ↓
//> java Main
//main : start
//  child : start (pid=19076)
//  child : start (pid=9308)
//  child : lock start (pid=19076)
//  child :   *** lock OK! *** (pid=19076)
//  child :   sleep 5 seconds ... (pid=19076)
//  child : lock start (pid=9308)
//  child :   *** lock NG! *** (pid=9308)
//  child :   sleep 1 second ... (pid=9308)
//  child :   *** lock NG! *** (pid=9308)
//  child :   sleep 1 second ... (pid=9308)
//  child :   *** lock NG! *** (pid=9308)
//  child :   sleep 1 second ... (pid=9308)
//  child :   *** lock NG! *** (pid=9308)
//  child :   sleep 1 second ... (pid=9308)
//  child :   *** lock NG! *** (pid=9308)
//  child :   sleep 1 second ... (pid=9308)
//  child : lock end (pid=19076)
//  child : end (pid=19076)
//  child :   *** lock OK! *** (pid=9308)
//  child :   sleep 5 seconds ... (pid=9308)
//  child : lock end (pid=9308)
//  child : end (pid=9308)
//main : end

Note :

  • This file-locking API is platform dependent. Please check the API specification for details.
  • The code examples in this article are running on Windows 10.

Constructors

FileLock (AsynchronousFileChannel channel, long position, long size, boolean shared)

Initializes a new instance of this class.

protected. I think it's rare to create a subclass of this class. Therefore, the code example is omitted.

FileLock (FileChannel channel, long position, long size, boolean shared)

Initializes a new instance of this class.

protected. I think it's rare to create a subclass of this class. Therefore, the code example is omitted.

Methods

Channel acquiredBy ()

Returns the channel upon whose file this lock was acquired.

final var file = Path.of("R:", "java-work", "lock.txt");
try (final var fc = FileChannel.open(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
    try (final var lock = fc.lock()) {
        final var ret = lock.acquiredBy();
        System.out.println(fc == ret); // true
    }
}

final FileChannel channel ()

Returns the file channel upon whose file this lock was acquired.

final var file = Path.of("R:", "java-work", "lock.txt");
try (final var fc = FileChannel.open(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
    try (final var lock = fc.lock()) {
        final var ret = lock.channel();
        System.out.println(fc == ret); // true
    }
}

final void close ()

This method invokes the release() method.

final var file = Path.of("R:", "java-work", "lock.txt");
try (final var fc = FileChannel.open(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
    try (final var lock = fc.lock()) {
        System.out.println(lock.isValid()); // true
    }
}

An example without the try-with-resources statement.

final var file = Path.of("R:", "java-work", "lock.txt");
try (final var fc = FileChannel.open(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
    final var lock = fc.lock();
    try {
        System.out.println(lock.isValid()); // true
    } finally {
        lock.close();
    }

    System.out.println(lock.isValid()); // false
}

final boolean isShared ()

Tells whether this lock is shared.

public class Child {
    public static void main(String[] args) throws IOException, InterruptedException {
        if (args.length != 2) {
            throw new IllegalArgumentException();
        }
        final var type = args[0];
        final var shared = "shared".equals(args[1]);

        println(type, "start");

        TimeUnit.SECONDS.sleep(1);

        final var file = Path.of("lock.txt");
        try (final var fc = FileChannel.open(file,
                StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.READ)) {

            println(type, "tryLock shared = " + shared);
            try (final var lock = fc.tryLock(0, Long.MAX_VALUE, shared)) {
                if (lock != null) {
                    println(type, "  *** lock OK! ***");

                    final var ret = lock.isShared();
                    println(type, "  isShared = " + ret);

                    TimeUnit.SECONDS.sleep(5);
                } else {
                    println(type, "  *** lock NG! ***");
                }
            }
        }
    }

    private static void println(String type, String text) {
        System.out.printf("  child %s : %s%n", type, text);
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        if (args.length != 2) {
            throw new IllegalArgumentException();
        }

        System.out.println("main : start");

        final var sharedA = args[0];
        final var sharedB = args[1];

        System.out.println("main : child A = " + sharedA);
        System.out.println("main : child B = " + sharedB);

        final var p1 = new ProcessBuilder("java", "Child", "A", sharedA).inheritIO().start();
        final var p2 = new ProcessBuilder("java", "Child", "B", sharedB).inheritIO().start();

        p1.waitFor();
        p2.waitFor();

        System.out.println("main : end");
    }
}

// Result
// ↓
//> java Main shared shared
//main : start
//main : child A = shared
//main : child B = shared
//  child A : start
//  child B : start
//  child A : tryLock shared = true
//  child A :   *** lock OK! ***
//  child A :   isShared = true
//  child B : tryLock shared = true
//  child B :   *** lock OK! ***
//  child B :   isShared = true
//main : end
//
//> java Main exclusive shared
//main : start
//main : child A = exclusive
//main : child B = shared
//  child A : start
//  child B : start
//  child A : tryLock shared = false
//  child A :   *** lock OK! ***
//  child A :   isShared = false
//  child B : tryLock shared = true
//  child B :   *** lock NG! ***
//main : end
//
//> java Main shared exclusive
//main : start
//main : child A = shared
//main : child B = exclusive
//  child A : start
//  child B : start
//  child A : tryLock shared = true
//  child A :   *** lock OK! ***
//  child A :   isShared = true
//  child B : tryLock shared = false
//  child B :   *** lock NG! ***
//main : end
//
//> java Main exclusive exclusive
//main : start
//main : child A = exclusive
//main : child B = exclusive
//  child A : start
//  child B : start
//  child A : tryLock shared = false
//  child A :   *** lock OK! ***
//  child A :   isShared = false
//  child B : tryLock shared = false
//  child B :   *** lock NG! ***
//main : end

abstract boolean isValid ()

Tells whether or not this lock is valid.

Please see close().

final boolean overlaps (long position, long size)

Tells whether or not this lock overlaps the given lock range.

final var file = Path.of("R:", "java-work", "lock.txt");
try (final var fc = FileChannel.open(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
    try (final var lock = fc.lock(100, 200, false)) {

        System.out.println(lock.position()); // 100
        System.out.println(lock.size()); // 200

        System.out.println(lock.overlaps(0, 99)); // false
        System.out.println(lock.overlaps(0, 100)); // false
        System.out.println(lock.overlaps(0, 101)); // true

        System.out.println(lock.overlaps(99, 1)); // false
        System.out.println(lock.overlaps(100, 1)); // true
        System.out.println(lock.overlaps(101, 1)); // true

        System.out.println(lock.overlaps(299, 1)); // true
        System.out.println(lock.overlaps(300, 1)); // false
        System.out.println(lock.overlaps(301, 1)); // false

        System.out.println(lock.overlaps(0, Long.MAX_VALUE)); // true
    }
}

final long position ()

Returns the position within the file of the first byte of the locked region.

public class Child {
    public static void main(String[] args) throws IOException, InterruptedException {
        if (args.length != 3) {
            throw new IllegalArgumentException();
        }
        final var type = args[0];
        final var position = Long.parseLong(args[1]);
        final var size = Integer.parseInt(args[2]);

        println(type, "start");

        TimeUnit.SECONDS.sleep(1);

        final var file = Path.of("lock.txt");
        try (final var fc = FileChannel.open(file,
                StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.READ)) {

            println(type, "tryLock position = %d size = %d".formatted(position, size));
            try (final var lock = fc.tryLock(position, size, false)) {
                if (lock != null) {
                    println(type, "  *** lock OK! ***");
                    println(type, "  position = " + lock.position());
                    println(type, "  size = " + lock.size());

                    fc.position(position);
                    final var buff = ByteBuffer.allocate(size);
                    fc.read(buff);
                    println(type, "  read = " + Arrays.toString(buff.array()));

                    TimeUnit.SECONDS.sleep(5);
                } else {
                    println(type, "  *** lock NG! ***");
                }
            }
        }

        println(type, "end");
    }

    private static void println(String type, String text) {
        System.out.printf("  child %s : %s%n", type, text);
    }
}
public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        if (args.length != 4) {
            throw new IllegalArgumentException();
        }

        System.out.println("main : start");

        final var positionA = args[0];
        final var sizeA = args[1];

        final var positionB = args[2];
        final var sizeB = args[3];

        System.out.println("main : child A position = " + positionA + " size = " + sizeA);
        System.out.println("main : child B position = " + positionB + " size = " + sizeB);

        final var file = Path.of("lock.txt");
        final byte[] bytes = {10, 20, 30, 40, 50, 60, 70};
        Files.write(file, bytes);

        final var p1 = new ProcessBuilder("java", "Child", "A", positionA, sizeA).inheritIO().start();
        final var p2 = new ProcessBuilder("java", "Child", "B", positionB, sizeB).inheritIO().start();

        p1.waitFor();
        p2.waitFor();

        System.out.println("main : end");
    }
}

// Result
// ↓
//> java Main 0 7 0 7
//main : start
//main : child A position = 0 size = 7
//main : child B position = 0 size = 7
//  child A : start
//  child B : start
//  child A : tryLock position = 0 size = 7
//  child A :   *** lock OK! ***
//  child A :   position = 0
//  child A :   size = 7
//  child A :   read = [10, 20, 30, 40, 50, 60, 70]
//  child B : tryLock position = 0 size = 7
//  child B :   *** lock NG! ***
//  child B : end
//  child A : end
//main : end
//
//> java Main 0 3 3 4
//main : start
//main : child A position = 0 size = 3
//main : child B position = 3 size = 4
//  child A : start
//  child B : start
//  child A : tryLock position = 0 size = 3
//  child A :   *** lock OK! ***
//  child A :   position = 0
//  child A :   size = 3
//  child A :   read = [10, 20, 30]
//  child B : tryLock position = 3 size = 4
//  child B :   *** lock OK! ***
//  child B :   position = 3
//  child B :   size = 4
//  child B :   read = [40, 50, 60, 70]
//  child A : end
//  child B : end
//main : end

abstract void release ()

Releases this lock.

Please see also : close()

final var file = Path.of("R:", "java-work", "lock.txt");
try (final var fc = FileChannel.open(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
    final var lock = fc.lock();
    try {
        System.out.println(lock.isValid()); // true
    } finally {
        lock.release();
    }

    System.out.println(lock.isValid()); // false
}

final long size ()

Returns the size of the locked region in bytes.

Please see position().

final String toString ()

Returns a string describing the range, type, and validity of this lock.

final var file = Path.of("R:", "java-work", "lock.txt");
try (final var fc = FileChannel.open(file,
        StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.READ)) {

    try (final var lock = fc.lock()) {
        final var str = lock.toString();
        System.out.println(str); // sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive valid]
    }

    try (final var lock = fc.lock(100, 200, true)) {
        final var str = lock.toString();
        System.out.println(str); // sun.nio.ch.FileLockImpl[100:200 shared valid]
    }
}

Related posts

To top of page