Java Programming Tutorials

Java programming tutorials with many code examples!

Java ReentrantLock


How to use Java ReentrantLock instead of old-school synchronization on lock object? In this post we’re going to show an example with basic features of ReentrantLock.

java.util.concurrent package has shipped in Java 5 and has introduced many classes that are replacements for simple synchronization mechanisms available in previous versions of Java. The new classes are not only simple replacements, but also have many more enhancements.


In one of previous posts – Java synchronized object – we’ve shown how to safely synchronize access to data in multi-threaded environment. In this post we’re going to use the same example, but replace object lock with ReentrantLock.

The code below calls Counter.dec() from a bunch of concurrently running threads. To guarantee its correctness we need to synchronize modifications:


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {

    private static class Counter {
        private ReentrantLock lock = new ReentrantLock();
        private int number;

        public Counter(int number) {
            this.number = number;

        public boolean dec() {
            // the same as "synchronized(lockObject)":
            try {
                if (number > 0) {
                    return true;
                return false;
            } finally {
                // have to unlock explicitely:

    private static class Worker implements Runnable {

        private static int nth = 0;

        private final int id = ++nth;
        private Counter counter;

        public Worker(Counter counter) {
            this.counter = counter;

        public void run() {
            System.out.println("Starting worker: " + id);
            while (counter.dec()) {
                System.out.printf("Decreased to %2d by worker: %2d%n",
                        counter.number, id);

    public static void main(String[] args) {
        Counter counter = new Counter(10);
        ExecutorService executor = Executors.newCachedThreadPool();
        for (int i = 1; i <= 10; ++i) {
            executor.execute(new Worker(counter));

        System.out.println("Number actually is: " + counter.number);

The code most noticeable difference with synchronization using synchronized(lockObject) is that we have to obtain lock explicitly using ReentrantLock.lock() method and we have to release the lock explicitly using ReentrantLock.unlock(). The unlock() method is in finally block, because we want always to release the lock, even in case of exception during processing.

As can be seen in the below output (sorted for readability) the code works as advertised:

Starting worker: 1
Starting worker: 2
Starting worker: 3
Starting worker: 4
Starting worker: 5
Starting worker: 6
Starting worker: 7
Starting worker: 8
Starting worker: 9
Starting worker: 10
Decreased to  9 by worker:  2
Decreased to  8 by worker: 10
Decreased to  7 by worker:  2
Decreased to  6 by worker: 10
Decreased to  5 by worker:  8
Decreased to  4 by worker:  1
Decreased to  3 by worker:  7
Decreased to  2 by worker:  5
Decreased to  1 by worker:  6
Decreased to  0 by worker:  4
Number actually is: 0

One may think “why to use ReentrantLock if it does the same thing”? The similarity is only on the surface, ReentrantLock, like other java.util.concurrent classes, have many more useful features as we’ll show in subsequent posts! :-)

Was it helpful? Share!
  • every object created in Java has one mutually exclusive lock associated with it. When you are using synchronized you are using that lock implicitly (with no other feature) whereas when you are using any of the lock implementation you are using that lock explicitly. Which means there are methods like lock() to acquire the lock and unlock() to release the lock.