Skip to content

Yet another programming solutions log

Sample bits from programming for the future generations.

Technologies Technologies
  • Algorithms and Data Structures
  • Java Tutorials
  • JUnit Tutorial
  • MongoDB Tutorial
  • Quartz Scheduler Tutorial
  • Spock Framework Tutorial
  • Spring Framework
  • Bash Tutorial
  • Clojure Tutorial
  • Design Patterns
  • Developer’s Tools
  • Productivity
  • About
Expand Search Form

Java ReentrantLock

farenda 2015-11-17 1

Problem:

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.

Solution:

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:

package com.farenda.java.util.concurrent;

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)":
            lock.lock();
            try {
                if (number > 0) {
                    Thread.yield();
                    --number;
                    return true;
                }
                return false;
            } finally {
                // have to unlock explicitely:
                lock.unlock();
            }
        }
    }

    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;
        }

        @Override
        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));
        }
        executor.shutdown();

        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! :-)

Share with the World!
Categories Java Tags java, java-concurrency
Previous: Java synchronize static
Next: Git Cheat Sheet

Recent Posts

  • Java 8 Date Time concepts
  • Maven dependency to local JAR
  • Caesar cipher in Java
  • Java casting trick
  • Java 8 flatMap practical example
  • Linked List – remove element
  • Linked List – insert element at position
  • Linked List add element at the end
  • Create Java Streams
  • Floyd Cycle detection in Java

Pages

  • About Farenda
  • Algorithms and Data Structures
  • Bash Tutorial
  • Bean Validation Tutorial
  • Clojure Tutorial
  • Design Patterns
  • Java 8 Streams and Lambda Expressions Tutorial
  • Java Basics Tutorial
  • Java Collections Tutorial
  • Java Concurrency Tutorial
  • Java IO Tutorial
  • Java Tutorials
  • Java Util Tutorial
  • Java XML Tutorial
  • JUnit Tutorial
  • MongoDB Tutorial
  • Quartz Scheduler Tutorial
  • Software Developer’s Tools
  • Spock Framework Tutorial
  • Spring Framework

Tags

algorithms bash bean-validation books clojure design-patterns embedmongo exercises git gof gradle groovy hateoas hsqldb i18n java java-basics java-collections java-concurrency java-io java-lang java-time java-util java-xml java8 java8-files junit linux lists log4j logging maven mongodb performance quartz refactoring regex rest slf4j solid spring spring-boot spring-core sql unit-tests

Yet another programming solutions log © 2022

sponsored