Java : ReentrantLock with Examples

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


Summary

A reentrant mutual exclusion Lock with the same basic behavior and semantics as the implicit monitor lock accessed using synchronized methods and statements, but with extended capabilities.

Class diagram

try (final var executor = Executors.newFixedThreadPool(3)) {
    final var lock = new ReentrantLock();

    for (int i = 1; i <= 3; i++) {
        final var id = i;
        TimeUnit.MILLISECONDS.sleep(100);

        executor.submit(() -> {
            System.out.println(id + " : lock ...");
            lock.lock();
            try {
                System.out.println(id + " : lock OK!");

                TimeUnit.SECONDS.sleep(2);
                System.out.println(id + " : sleep completed (unlock!)");
            } catch (InterruptedException e) {
                System.out.println("InterruptedException!");
            } finally {
                lock.unlock();
            }
        });
    }
}

// Result
// ↓
//1 : lock ...
//1 : lock OK!
//2 : lock ...
//3 : lock ...
//1 : sleep completed (unlock!)
//2 : lock OK!
//2 : sleep completed (unlock!)
//3 : lock OK!
//3 : sleep completed (unlock!)

Constructors

ReentrantLock ()

Creates an instance of ReentrantLock.

try (final var executor = Executors.newFixedThreadPool(3)) {
    final var lock = new ReentrantLock();

    for (int i = 1; i <= 3; i++) {
        final var id = i;
        TimeUnit.MILLISECONDS.sleep(100);

        executor.submit(() -> {
            System.out.println(id + " : lock ...");
            lock.lock();
            try {
                System.out.println(id + " : lock OK!");

                TimeUnit.SECONDS.sleep(2);
                System.out.println(id + " : sleep completed (unlock!)");
            } catch (InterruptedException e) {
                System.out.println("InterruptedException!");
            } finally {
                lock.unlock();
            }
        });
    }
}

// Result
// ↓
//1 : lock ...
//1 : lock OK!
//2 : lock ...
//3 : lock ...
//1 : sleep completed (unlock!)
//2 : lock OK!
//2 : sleep completed (unlock!)
//3 : lock OK!
//3 : sleep completed (unlock!)

ReentrantLock (boolean fair)

Creates an instance of ReentrantLock with the given fairness policy.

Please see also : ReentrantLock()

void testFair(boolean fair) throws InterruptedException {
    final var lock = new ReentrantLock(fair);
    System.out.println("isFair = " + lock.isFair());

    final var order = new ArrayList<Integer>();
    try (final var executor = Executors.newFixedThreadPool(2)) {
        lock.lock();
        try {
            executor.submit(() -> {
                try {
                    lock.lock();
                    order.add(1);
                } finally {
                    lock.unlock();
                }
                try {
                    lock.lock();
                    order.add(2);
                } finally {
                    lock.unlock();
                }
            });

            TimeUnit.MILLISECONDS.sleep(100);

            executor.submit(() -> {
                try {
                    lock.lock();
                    order.add(3);
                } finally {
                    lock.unlock();
                }
            });

            TimeUnit.MILLISECONDS.sleep(100);

        } finally {
            lock.unlock();
        }
    }

    System.out.println("order = " + order);
}
testFair(true);

// Result
// ↓
//isFair = true
//order = [1, 3, 2]

testFair(false);

// Result
// ↓
//isFair = false
//order = [1, 2, 3]

Methods

int getHoldCount ()

Queries the number of holds on this lock by the current thread.

final var lock = new ReentrantLock();

System.out.println(lock.getHoldCount()); // 0
System.out.println(lock.isHeldByCurrentThread()); // false

lock.lock();
try {
    System.out.println(lock.getHoldCount()); // 1
    System.out.println(lock.isHeldByCurrentThread()); // true

    lock.lock();
    try {
        System.out.println(lock.getHoldCount()); // 2
        System.out.println(lock.isHeldByCurrentThread()); // true

        lock.lock();
        try {
            System.out.println(lock.getHoldCount()); // 3
            System.out.println(lock.isHeldByCurrentThread()); // true
        } finally {
            lock.unlock();
        }
        System.out.println(lock.getHoldCount()); // 2
        System.out.println(lock.isHeldByCurrentThread()); // true

    } finally {
        lock.unlock();
    }
    System.out.println(lock.getHoldCount()); // 1
    System.out.println(lock.isHeldByCurrentThread()); // true

} finally {
    lock.unlock();
}
System.out.println(lock.getHoldCount()); // 0
System.out.println(lock.isHeldByCurrentThread()); // false

protected Thread getOwner ()

Returns the thread that currently owns this lock, or null if not owned.

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

protected Collection<Thread> getQueuedThreads ()

Returns a collection containing threads that may be waiting to acquire this lock.

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

final int getQueueLength ()

Returns an estimate of the number of threads waiting to acquire this lock.

final var lock = new ReentrantLock();

try (final var executor = Executors.newFixedThreadPool(5)) {
    for (int i = 1; i <= 5; i++) {
        final var id = i;
        TimeUnit.MILLISECONDS.sleep(100);

        executor.submit(() -> {
            System.out.printf("%d : lock ... : queue length = %d (%b)%n",
                    id, lock.getQueueLength(), lock.hasQueuedThreads());

            lock.lock();
            try {
                System.out.printf("%d : lock OK! : queue length = %d (%b)%n",
                        id, lock.getQueueLength(), lock.hasQueuedThreads());

                TimeUnit.SECONDS.sleep(3);
                System.out.println(id + " : sleep completed (unlock!)");
            } catch (InterruptedException e) {
                System.out.println("InterruptedException!");
            } finally {
                lock.unlock();
            }
        });
    }
}

// Result
// ↓
//1 : lock ... : queue length = 0 (false)
//1 : lock OK! : queue length = 0 (false)
//2 : lock ... : queue length = 0 (false)
//3 : lock ... : queue length = 1 (true)
//4 : lock ... : queue length = 2 (true)
//5 : lock ... : queue length = 3 (true)
//1 : sleep completed (unlock!)
//2 : lock OK! : queue length = 3 (true)
//2 : sleep completed (unlock!)
//3 : lock OK! : queue length = 2 (true)
//3 : sleep completed (unlock!)
//4 : lock OK! : queue length = 1 (true)
//4 : sleep completed (unlock!)
//5 : lock OK! : queue length = 0 (false)
//5 : sleep completed (unlock!)

protected Collection<Thread> getWaitingThreads (Condition condition)

Returns a collection containing those threads that may be waiting on the given condition associated with this lock.

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

int getWaitQueueLength (Condition condition)

Returns an estimate of the number of threads waiting on the given condition associated with this lock.

try (var executor = Executors.newFixedThreadPool(3)) {
    final var lock = new ReentrantLock();
    final var cond = lock.newCondition();

    for (int i = 1; i <= 3; i++) {
        final var id = i;
        TimeUnit.MILLISECONDS.sleep(100);

        executor.submit(() -> {
            lock.lock();
            try {
                System.out.printf("%d : await ... : wait queue length = %d (%b)%n",
                        id, lock.getWaitQueueLength(cond), lock.hasWaiters(cond));

                cond.await();
                System.out.printf("%d : await OK!  : wait queue length = %d (%b)%n",
                        id, lock.getWaitQueueLength(cond), lock.hasWaiters(cond));
            } catch (InterruptedException e) {
                System.out.println("InterruptedException!");
            } finally {
                lock.unlock();
            }
        });
    }

    TimeUnit.SECONDS.sleep(2);

    for (int i = 0; i < 3; i++) {
        lock.lock();
        try {
            System.out.println("signal!");
            cond.signal();
        } finally {
            lock.unlock();
        }

        TimeUnit.SECONDS.sleep(1);
    }
}

// Result
// ↓
//1 : await ... : wait queue length = 0 (false)
//2 : await ... : wait queue length = 1 (true)
//3 : await ... : wait queue length = 2 (true)
//signal!
//1 : await OK!  : wait queue length = 2 (true)
//signal!
//2 : await OK!  : wait queue length = 1 (true)
//signal!
//3 : await OK!  : wait queue length = 0 (false)

final boolean hasQueuedThread (Thread thread)

Queries whether the given thread is waiting to acquire this lock.

try (var executor = Executors.newSingleThreadExecutor()) {
    final var lock = new ReentrantLock();
    final var main = Thread.currentThread();

    executor.submit(() -> {
        try {
            lock.lock();
            try {
                System.out.println("A : lock OK!");

                TimeUnit.SECONDS.sleep(1);
                System.out.println("A : main is waiting = " + lock.hasQueuedThread(main));

                TimeUnit.SECONDS.sleep(2);
                System.out.println("A : main is waiting = " + lock.hasQueuedThread(main));
                System.out.println("A : unlock!");
            } finally {
                lock.unlock();
            }

            TimeUnit.SECONDS.sleep(2);
            System.out.println("A : main is waiting = " + lock.hasQueuedThread(main));

        } catch (InterruptedException e) {
            System.out.println("InterruptedException!");
        }
    });

    TimeUnit.SECONDS.sleep(2);

    System.out.println("main : lock ...");
    lock.lock();
    try {
        System.out.println("main : lock OK!");

        TimeUnit.SECONDS.sleep(1);
        System.out.println("main : unlock!");
    } finally {
        lock.unlock();
    }
}

// Result
// ↓
//A : lock OK!
//A : main is waiting = false
//main : lock ...
//A : main is waiting = true
//A : unlock!
//main : lock OK!
//main : unlock!
//A : main is waiting = false

final boolean hasQueuedThreads ()

Queries whether any threads are waiting to acquire this lock.

Please see getQueueLength().

boolean hasWaiters (Condition condition)

Queries whether any threads are waiting on the given condition associated with this lock.

Please see getWaitQueueLength(Condition condition).

final boolean isFair ()

Returns true if this lock has fairness set true.

Please see ReentrantLock(boolean fair).

boolean isHeldByCurrentThread ()

Queries if this lock is held by the current thread.

Please see getHoldCount().

boolean isLocked ()

Queries if this lock is held by any thread.

final var lock = new ReentrantLock();

try (final var executor = Executors.newFixedThreadPool(3)) {
    for (int i = 1; i <= 3; i++) {
        final var id = i;
        TimeUnit.MILLISECONDS.sleep(100);

        executor.submit(() -> {
            System.out.printf("%d : lock ... : isLocked = %b%n", id, lock.isLocked());
            lock.lock();
            try {
                System.out.printf("%d : lock OK! : isLocked = %b%n", id, lock.isLocked());

                TimeUnit.SECONDS.sleep(2);
                System.out.printf("%d : sleep completed (unlock!)%n", id);
            } catch (InterruptedException e) {
                System.out.println("InterruptedException!");
            } finally {
                lock.unlock();
            }
        });
    }
}
System.out.printf("main : isLocked = %b%n", lock.isLocked());

// Result
// ↓
//1 : lock ... : isLocked = false
//1 : lock OK! : isLocked = true
//2 : lock ... : isLocked = true
//3 : lock ... : isLocked = true
//1 : sleep completed (unlock!)
//2 : lock OK! : isLocked = true
//2 : sleep completed (unlock!)
//3 : lock OK! : isLocked = true
//3 : sleep completed (unlock!)
//main : isLocked = false

void lock ()

Acquires the lock.

Please see ReentrantLock().

void lockInterruptibly ()

Acquires the lock unless the current thread is interrupted.

try (final var executor = Executors.newFixedThreadPool(3)) {
    final var lock = new ReentrantLock();

    for (int i = 1; i <= 3; i++) {
        final var id = i;
        TimeUnit.MILLISECONDS.sleep(100);

        executor.submit(() -> {
            try {
                System.out.println(id + " : lock ...");
                lock.lockInterruptibly();
                try {
                    System.out.println(id + " : lock OK!");

                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(id + " : sleep completed (unlock!)");
                } finally {
                    lock.unlock();
                }
            } catch (InterruptedException e) {
                System.out.println("InterruptedException!");
            }
        });
    }
}

// Result
// ↓
//1 : lock ...
//1 : lock OK!
//2 : lock ...
//3 : lock ...
//1 : sleep completed (unlock!)
//2 : lock OK!
//2 : sleep completed (unlock!)
//3 : lock OK!
//3 : sleep completed (unlock!)
try (final var executor = Executors.newFixedThreadPool(2)) {
    final var lock = new ReentrantLock();

    class Task implements Runnable {
        private final String name;

        Task(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            try {
                System.out.println(name + " : lock ...");
                lock.lockInterruptibly();
                try {
                    System.out.println(name + " : lock OK!");

                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(name + " : sleep completed (unlock!)");
                } finally {
                    lock.unlock();
                }
            } catch (InterruptedException e) {
                System.out.println(name + " : InterruptedException!");
            }
        }
    }

    executor.submit(new Task("A"));
    TimeUnit.MILLISECONDS.sleep(100);

    final var futureB = executor.submit(new Task("B"));
    TimeUnit.MILLISECONDS.sleep(100);

    System.out.println("cancel task(B)");
    futureB.cancel(true);
}

// Result
// ↓
//A : lock ...
//A : lock OK!
//B : lock ...
//cancel task(B)
//B : InterruptedException!
//A : sleep completed (unlock!)

Condition newCondition ()

Returns a Condition instance for use with this Lock instance.

final long current = System.nanoTime();
final DoubleSupplier elapsedTime = () -> (System.nanoTime() - current) / 1000000000.0;

try (var executor = Executors.newSingleThreadExecutor()) {
    final var lock = new ReentrantLock();
    final var cond = lock.newCondition();

    executor.submit(() -> {
        System.out.printf("lock ... (%f sec.)%n", elapsedTime.getAsDouble());
        lock.lock();
        try {
            System.out.printf("await ... (%f sec.)%n", elapsedTime.getAsDouble());
            cond.await();
            System.out.printf("await OK! (%f sec.)%n", elapsedTime.getAsDouble());
        } catch (InterruptedException e) {
            System.out.println("InterruptedException!");
        } finally {
            lock.unlock();
        }
    });

    TimeUnit.SECONDS.sleep(5);

    lock.lock();
    try {
        System.out.printf("signal! (%f sec.)%n", elapsedTime.getAsDouble());
        cond.signal();
    } finally {
        lock.unlock();
    }
}

// Result
// ↓
//lock ... (0.003795 sec.)
//await ... (0.006260 sec.)
//signal! (5.019196 sec.)
//await OK! (5.019534 sec.)

String toString ()

Returns a string identifying this lock, as well as its lock state.

final var lock = new ReentrantLock();
final var str1 = lock.toString();

// java.util.concurrent.locks.ReentrantLock@20bd8be5[Unlocked]
System.out.println(str1);

lock.lock();
try {
    final var str2 = lock.toString();

    // java.util.concurrent.locks.ReentrantLock@20bd8be5[Locked by thread Test worker]
    System.out.println(str2);
} finally {
    lock.unlock();
}

boolean tryLock ()

Acquires the lock only if it is not held by another thread at the time of invocation.

final long current = System.nanoTime();
final DoubleSupplier elapsedTime = () -> (System.nanoTime() - current) / 1000000000.0;

try (var executor = Executors.newFixedThreadPool(2)) {
    final var lock = new ReentrantLock();

    executor.submit(() -> {
        lock.lock();
        try {
            System.out.println("A : lock OK!");

            TimeUnit.SECONDS.sleep(5);
            System.out.println("A : sleep completed (unlock!)");
        } catch (InterruptedException e) {
            System.out.println("InterruptedException!");
        } finally {
            lock.unlock();
        }
    });

    TimeUnit.MILLISECONDS.sleep(100);

    executor.submit(() -> {
        try {
            while (true) {
                if (lock.tryLock()) {
                    try {
                        System.out.printf("B : tryLock = true (%f sec.)%n",
                                elapsedTime.getAsDouble());
                        break;
                    } finally {
                        lock.unlock();
                    }
                }

                System.out.printf("B : tryLock = false (%f sec.)%n",
                        elapsedTime.getAsDouble());
                TimeUnit.SECONDS.sleep(2);
            }
        } catch (InterruptedException e) {
            System.out.println("InterruptedException!");
        }
    });
}

// Result
// ↓
//A : lock OK!
//B : tryLock = false (0.113863 sec.)
//B : tryLock = false (2.125517 sec.)
//B : tryLock = false (4.135200 sec.)
//A : sleep completed (unlock!)
//B : tryLock = true (6.139156 sec.)

boolean tryLock (long timeout, TimeUnit unit)

Acquires the lock if it is not held by another thread within the given waiting time and the current thread has not been interrupted.

final long current = System.nanoTime();
final DoubleSupplier elapsedTime = () -> (System.nanoTime() - current) / 1000000000.0;

try (var executor = Executors.newFixedThreadPool(2)) {
    final var lock = new ReentrantLock();

    executor.submit(() -> {
        lock.lock();
        try {
            System.out.println("A : lock OK!");

            TimeUnit.SECONDS.sleep(5);
            System.out.println("A : sleep completed (unlock!)");
        } catch (InterruptedException e) {
            System.out.println("InterruptedException!");
        } finally {
            lock.unlock();
        }
    });

    TimeUnit.MILLISECONDS.sleep(100);

    executor.submit(() -> {
        try {
            while (true) {
                if (lock.tryLock(2, TimeUnit.SECONDS)) {
                    try {
                        System.out.printf("B : tryLock = true (%f sec.)%n",
                                elapsedTime.getAsDouble());
                        break;
                    } finally {
                        lock.unlock();
                    }
                }

                System.out.printf("B : tryLock = false (%f sec.)%n",
                        elapsedTime.getAsDouble());
            }
        } catch (InterruptedException e) {
            System.out.println("InterruptedException!");
        }
    });
}

// Result
// ↓
//A : lock OK!
//B : tryLock = false (2.114785 sec.)
//B : tryLock = false (4.131868 sec.)
//A : sleep completed (unlock!)
//B : tryLock = true (5.011976 sec.)

void unlock ()

Attempts to release this lock.

Please see ReentrantLock().


Related posts

To top of page