Clean Synchronization Using ReentrantLock and Lambdas

Home  >>  Common  >>  Clean Synchronization Using ReentrantLock and Lambdas

Clean Synchronization Using ReentrantLock and Lambdas

Recently I was reading an informative post about the differences between synchronized vs ReentrantLock by Javin Paul1. He emphasises on the advantages of the latter, but does not withhold some downsides, which are related to the cumbersome try-finally block needed for proper usage.

While agreeing with his statements I brooded about a thought, that always bothers me when it comes down to synchronization. Both approaches mix up separate concerns – synchronization and the functionality of the synchronized content – which hampers testing those concerns one by one.

Being the explorative type, I picked up a solution for this problem that I already tried in the past. However, at that time I did not like the programming pattern too much. This was because of its verboseness due to an anonymous class. But having Java 8 and Lambda expressions at hand I thought it might be worth reconsidering. So I copied the ‘counter’ part of Javin Paul’s example, wrote a simple test case and started refactoring. This was the initial situation:

class Counter {

  private final Lock lock;

  private int count;

  Counter() {
    lock = new ReentrantLock();
  }

  int next() {
    lock.lock();
    try {
      return count++;
    } finally {
      lock.unlock();
    }
  }
}

One can clearly see the ugly try-finally block that produces a lot of noise around the actual functionality2. The idea is to move this block into its own class that serves as a synchronization aspect to a kind of operation that does the incremental. The next snippet shows how such a newly created Operation interface may look like and how it can be used by a Lambda expression3:

class Counter {

  private final Lock lock;

  private int count;

  interface Operation<T> {
    T execute();
  }

  Counter() {
    lock = new ReentrantLock();
  }

  int next() {
    lock.lock();
    try {
      Operation<Integer> operation = () -> { return count++; };
      return operation.execute();
    } finally {
      lock.unlock();
    }
  }
}

In the following class extracting step the Synchronizer type is introduced to serve as an executor that ensures a given Operation is performed within proper synchronization boundaries:

class Counter {

  private final Synchronizer synchronizer;

  private int count;

  interface Operation<T> {
    T execute();
  }

  static class Synchronizer {

    private final Lock lock;

    Synchronizer() {
      lock = new ReentrantLock();
    }

    private int execute( Operation<Integer> operation ) {
      lock.lock();
      try {
        return operation.execute();
      } finally {
        lock.unlock();
      }
    }
  }

  Counter() {
    synchronizer = new Synchronizer();
  }

  int next() {
    return synchronizer.execute( () -> { return count++; } );
  }
}

If I am not completely mistaken this should do the same as the initial class. Well, the tests were green, but plain JUnit tests do usually not help much regarding concurrency. But with one last change it is at least possible to verify the proper invocation sequence by a unit test to ensure synchronization:

public class Counter {

  final Synchronizer<Integer> synchronizer;
  final Operation<Integer> incrementer;

  private int count;

  public Counter( Synchronizer<Integer> synchronizer ) {
    this.synchronizer = synchronizer;
    this.incrementer = () -> { return count++; };
  }

  public int next() {
    return synchronizer.execute( incrementer );
  }
}

As you can see the Operation and Synchronizer have been moved to their own files. This way the synchronization aspect is provided and can be tested as a seperate unit. The Counter class now uses the constructor to inject a synchronizer instance4. Furthermore the incrementation operation has been assigned to a field named ‘incrementer’. To ease testing a bit the final fields’ visibility has been opened to default. A test using Mockito for e.g. spying on the synchronizer could now ensure the proper synchronization call like this:

  @Test
  public void synchronization() {
    Synchronizer<Integer> synchronizer = spy( new Synchronizer<>() );
    Counter counter = new Counter( synchronizer );

    counter.next();

    verify( synchronizer ).execute( counter.incrementer );
  }

Usually, I am not overly excited about using method invocation verification, as this generates a very tight coupling between unit and test case. But given the circumstances above, it does not look as a too bad compromise to me. However I am just doing first warmups with Java 8 and Lambda expressions and maybe I am missing something on the concurrency side too – so what do you think?

See also  Stress/Load-Testing of Asynchronous HTTP/REST Services with JMeter


  1. ReentrantLock Example in Java, Difference between synchronized vs ReentrantLock, Javin Paul, March 7, 2013
  2. Obviously enough noise to confuse me, because my first test version failed…
  3. I decided to go with a type parameter return value instead of int. This way the resulting synchronization mechanism can be better reused. But I am not sure if e.g. autoboxing is uncritical here due to performance or whatsoever reasons. So for a general approach, there are probably some more things to consider, which are out of the scope of this post, though
  4. If changing the constructor is for any reason not possible one might introduce a delegating default constructor that injects the new instance of Synchronizer into the parameterized one like this: this( new Synchronizer() );. This approach might be an acceptable overhead for testing purpose
Frank Appel
Follow me
Latest posts by Frank Appel (see all)

5 Comments so far:

  1. Ruslan says:

    Why counters aren’t volatile?:
    private int count;

    • Frank Appel says:

      To quote a tutorial on javamex.com:

      – a primitive variable may be declared volatile (whereas you can’t synchronize on a primitive with synchronized);
      – an access to a volatile variable never has the potential to block: we’re only ever doing a simple read or write, so unlike a synchronized block we will never hold on to any lock;
      – because accessing a volatile variable never holds a lock, it is not suitable for cases where we want to read-update-write as an atomic operation (unless we’re prepared to “miss an update”);
      – a volatile variable that is an object reference may be null (because you’re effectively synchronizing on the reference, not the actual object).

      Given this short explanation the third list item is the crucial point here: If I am not mistaken count++ is a read-update-write and not a simple access operation on the count variable. Because of this increasing count has to be explicitly synchronized in a concurrent environment.

  2. […] >> Clean Synchronization Using ReentrantLock and Lambdas […]

  3. Tomasz N. says:

    Hi, nice post. I wrote a similar utility class some time ago Simplifying ReadWriteLock with Java 8 and lambdas. BTW notice that you don’t need custom Operation functional interface, built in java.util.function.Supplier would do.

  4. infoj says:

    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 (like ReentrantLock) you are using that lock explicitly. Which means there are methods like lock() to acquire the lock and unlock() to release the lock.
    http://netjs.blogspot.com/2016/02/reentrantlock-in-java-concurrency.html